frontend, api: allow custom emails as commenters
I'm really sorry this came out as one huge commit, but I'm afraid I can't split this up. Closes https://gitlab.com/commento/commento-ce/issues/9
This commit is contained in:
parent
e42f77b4eb
commit
2020405e8b
@ -8,7 +8,7 @@ import (
|
|||||||
func TestCommentApproveBasics(t *testing.T) {
|
func TestCommentApproveBasics(t *testing.T) {
|
||||||
failTestOnError(t, setupTestEnv())
|
failTestOnError(t, setupTestEnv())
|
||||||
|
|
||||||
commenterHex, _ := commenterNew("test@example.com", "Test", "undefined", "https://example.com/photo.jpg", "google")
|
commenterHex, _ := commenterNew("test@example.com", "Test", "undefined", "https://example.com/photo.jpg", "google", "")
|
||||||
|
|
||||||
commentHex, _ := commentNew(commenterHex, "example.com", "/path.html", "root", "**foo**", "unapproved", time.Now().UTC())
|
commentHex, _ := commentNew(commenterHex, "example.com", "/path.html", "root", "**foo**", "unapproved", time.Now().UTC())
|
||||||
|
|
||||||
|
@ -151,5 +151,6 @@ func commentListHandler(w http.ResponseWriter, r *http.Request) {
|
|||||||
"requireIdentification": d.RequireIdentification,
|
"requireIdentification": d.RequireIdentification,
|
||||||
"isFrozen": d.State == "frozen",
|
"isFrozen": d.State == "frozen",
|
||||||
"isModerator": isModerator,
|
"isModerator": isModerator,
|
||||||
|
"configuredOauths": configuredOauths,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,7 @@ import (
|
|||||||
func TestCommentListBasics(t *testing.T) {
|
func TestCommentListBasics(t *testing.T) {
|
||||||
failTestOnError(t, setupTestEnv())
|
failTestOnError(t, setupTestEnv())
|
||||||
|
|
||||||
commenterHex, _ := commenterNew("test@example.com", "Test", "undefined", "http://example.com/photo.jpg", "google")
|
commenterHex, _ := commenterNew("test@example.com", "Test", "undefined", "http://example.com/photo.jpg", "google", "")
|
||||||
|
|
||||||
commentNew(commenterHex, "example.com", "/path.html", "root", "**foo**", "approved", time.Now().UTC())
|
commentNew(commenterHex, "example.com", "/path.html", "root", "**foo**", "approved", time.Now().UTC())
|
||||||
commentNew(commenterHex, "example.com", "/path.html", "root", "**bar**", "approved", time.Now().UTC())
|
commentNew(commenterHex, "example.com", "/path.html", "root", "**bar**", "approved", time.Now().UTC())
|
||||||
@ -65,7 +65,7 @@ func TestCommentListEmpty(t *testing.T) {
|
|||||||
func TestCommentListSelfUnapproved(t *testing.T) {
|
func TestCommentListSelfUnapproved(t *testing.T) {
|
||||||
failTestOnError(t, setupTestEnv())
|
failTestOnError(t, setupTestEnv())
|
||||||
|
|
||||||
commenterHex, _ := commenterNew("test@example.com", "Test", "undefined", "http://example.com/photo.jpg", "google")
|
commenterHex, _ := commenterNew("test@example.com", "Test", "undefined", "http://example.com/photo.jpg", "google", "")
|
||||||
|
|
||||||
commentNew(commenterHex, "example.com", "/path.html", "root", "**foo**", "unapproved", time.Now().UTC())
|
commentNew(commenterHex, "example.com", "/path.html", "root", "**foo**", "unapproved", time.Now().UTC())
|
||||||
|
|
||||||
|
@ -116,5 +116,5 @@ func commentNewHandler(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
writeBody(w, response{"success": true, "commentHex": commentHex})
|
writeBody(w, response{"success": true, "commentHex": commentHex, "approved": state == "approved"})
|
||||||
}
|
}
|
||||||
|
@ -8,9 +8,9 @@ import (
|
|||||||
func TestCommentVoteBasics(t *testing.T) {
|
func TestCommentVoteBasics(t *testing.T) {
|
||||||
failTestOnError(t, setupTestEnv())
|
failTestOnError(t, setupTestEnv())
|
||||||
|
|
||||||
cr0, _ := commenterNew("test1@example.com", "Test1", "undefined", "http://example.com/photo.jpg", "google")
|
cr0, _ := commenterNew("test1@example.com", "Test1", "undefined", "http://example.com/photo.jpg", "google", "")
|
||||||
cr1, _ := commenterNew("test2@example.com", "Test2", "undefined", "http://example.com/photo.jpg", "google")
|
cr1, _ := commenterNew("test2@example.com", "Test2", "undefined", "http://example.com/photo.jpg", "google", "")
|
||||||
cr2, _ := commenterNew("test3@example.com", "Test3", "undefined", "http://example.com/photo.jpg", "google")
|
cr2, _ := commenterNew("test3@example.com", "Test3", "undefined", "http://example.com/photo.jpg", "google", "")
|
||||||
|
|
||||||
c0, _ := commentNew(cr0, "example.com", "/path.html", "root", "**foo**", "approved", time.Now().UTC())
|
c0, _ := commentNew(cr0, "example.com", "/path.html", "root", "**foo**", "approved", time.Now().UTC())
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@ import (
|
|||||||
func TestCommenterGetByHexBasics(t *testing.T) {
|
func TestCommenterGetByHexBasics(t *testing.T) {
|
||||||
failTestOnError(t, setupTestEnv())
|
failTestOnError(t, setupTestEnv())
|
||||||
|
|
||||||
commenterHex, _ := commenterNew("test@example.com", "Test", "undefined", "https://example.com/photo.jpg", "google")
|
commenterHex, _ := commenterNew("test@example.com", "Test", "undefined", "https://example.com/photo.jpg", "google", "")
|
||||||
|
|
||||||
c, err := commenterGetByHex(commenterHex)
|
c, err := commenterGetByHex(commenterHex)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -33,7 +33,7 @@ func TestCommenterGetByHexEmpty(t *testing.T) {
|
|||||||
func TestCommenterGetBySession(t *testing.T) {
|
func TestCommenterGetBySession(t *testing.T) {
|
||||||
failTestOnError(t, setupTestEnv())
|
failTestOnError(t, setupTestEnv())
|
||||||
|
|
||||||
commenterHex, _ := commenterNew("test@example.com", "Test", "undefined", "https://example.com/photo.jpg", "google")
|
commenterHex, _ := commenterNew("test@example.com", "Test", "undefined", "https://example.com/photo.jpg", "google", "")
|
||||||
|
|
||||||
session, _ := commenterSessionNew()
|
session, _ := commenterSessionNew()
|
||||||
|
|
||||||
@ -63,7 +63,7 @@ func TestCommenterGetBySessionEmpty(t *testing.T) {
|
|||||||
func TestCommenterGetByName(t *testing.T) {
|
func TestCommenterGetByName(t *testing.T) {
|
||||||
failTestOnError(t, setupTestEnv())
|
failTestOnError(t, setupTestEnv())
|
||||||
|
|
||||||
commenterHex, _ := commenterNew("test@example.com", "Test", "undefined", "https://example.com/photo.jpg", "google")
|
commenterHex, _ := commenterNew("test@example.com", "Test", "undefined", "https://example.com/photo.jpg", "google", "")
|
||||||
|
|
||||||
session, _ := commenterSessionNew()
|
session, _ := commenterSessionNew()
|
||||||
|
|
||||||
|
71
api/commenter_login.go
Normal file
71
api/commenter_login.go
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"golang.org/x/crypto/bcrypt"
|
||||||
|
"net/http"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func commenterLogin(email string, password string) (string, error) {
|
||||||
|
if email == "" || password == "" {
|
||||||
|
return "", errorMissingField
|
||||||
|
}
|
||||||
|
|
||||||
|
statement := `
|
||||||
|
SELECT commenterHex, passwordHash
|
||||||
|
FROM commenters
|
||||||
|
WHERE email = $1 AND provider = 'commento';
|
||||||
|
`
|
||||||
|
row := db.QueryRow(statement, email)
|
||||||
|
|
||||||
|
var commenterHex string
|
||||||
|
var passwordHash string
|
||||||
|
if err := row.Scan(&commenterHex, &passwordHash); err != nil {
|
||||||
|
return "", errorInvalidEmailPassword
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := bcrypt.CompareHashAndPassword([]byte(passwordHash), []byte(password)); err != nil {
|
||||||
|
// TODO: is this the only possible error?
|
||||||
|
return "", errorInvalidEmailPassword
|
||||||
|
}
|
||||||
|
|
||||||
|
session, err := randomHex(32)
|
||||||
|
if err != nil {
|
||||||
|
logger.Errorf("cannot create session hex: %v", err)
|
||||||
|
return "", errorInternal
|
||||||
|
}
|
||||||
|
|
||||||
|
statement = `
|
||||||
|
INSERT INTO
|
||||||
|
commenterSessions (session, commenterHex, creationDate)
|
||||||
|
VALUES ($1, $2, $3 );
|
||||||
|
`
|
||||||
|
_, err = db.Exec(statement, session, commenterHex, time.Now().UTC())
|
||||||
|
if err != nil {
|
||||||
|
logger.Errorf("cannot insert session token: %v\n", err)
|
||||||
|
return "", errorInternal
|
||||||
|
}
|
||||||
|
|
||||||
|
return session, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func commenterLoginHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
type request struct {
|
||||||
|
Email *string `json:"email"`
|
||||||
|
Password *string `json:"password"`
|
||||||
|
}
|
||||||
|
|
||||||
|
var x request
|
||||||
|
if err := unmarshalBody(r, &x); err != nil {
|
||||||
|
writeBody(w, response{"success": false, "message": err.Error()})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
session, err := commenterLogin(*x.Email, *x.Password)
|
||||||
|
if err != nil {
|
||||||
|
writeBody(w, response{"success": false, "message": err.Error()})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
writeBody(w, response{"success": true, "session": session})
|
||||||
|
}
|
58
api/commenter_login_test.go
Normal file
58
api/commenter_login_test.go
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestCommenterLoginBasics(t *testing.T) {
|
||||||
|
failTestOnError(t, setupTestEnv())
|
||||||
|
|
||||||
|
if _, err := commenterLogin("test@example.com", "hunter2"); err == nil {
|
||||||
|
t.Errorf("expected error not found when logging in without creating an account")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
commenterNew("test@example.com", "Test", "undefined", "undefined", "commento", "hunter2")
|
||||||
|
|
||||||
|
if _, err := commenterLogin("test@example.com", "hunter2"); err != nil {
|
||||||
|
t.Errorf("unexpected error when logging in: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := commenterLogin("test@example.com", "h******"); err == nil {
|
||||||
|
t.Errorf("expected error not found when given wrong password")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if session, err := commenterLogin("test@example.com", "hunter2"); session == "" {
|
||||||
|
t.Errorf("empty session on successful login: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCommenterLoginEmpty(t *testing.T) {
|
||||||
|
failTestOnError(t, setupTestEnv())
|
||||||
|
|
||||||
|
if _, err := commenterLogin("test@example.com", ""); err == nil {
|
||||||
|
t.Errorf("expected error not found when passing empty password")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
commenterNew("test@example.com", "Test", "undefined", "", "commenter", "hunter2")
|
||||||
|
|
||||||
|
if _, err := commenterLogin("test@example.com", ""); err == nil {
|
||||||
|
t.Errorf("expected error not found when passing empty password")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCommenterLoginNonCommento(t *testing.T) {
|
||||||
|
failTestOnError(t, setupTestEnv())
|
||||||
|
|
||||||
|
commenterNew("test@example.com", "Test", "undefined", "undefined", "google", "")
|
||||||
|
|
||||||
|
if _, err := commenterLogin("test@example.com", "hunter2"); err == nil {
|
||||||
|
t.Errorf("expected error not found logging into a non-Commento account")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
@ -1,28 +1,74 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"golang.org/x/crypto/bcrypt"
|
||||||
|
"net/http"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
func commenterNew(email string, name string, link string, photo string, provider string) (string, error) {
|
func commenterNew(email string, name string, link string, photo string, provider string, password string) (string, error) {
|
||||||
if email == "" || name == "" || link == "" || photo == "" || provider == "" {
|
if email == "" || name == "" || link == "" || photo == "" || provider == "" {
|
||||||
return "", errorMissingField
|
return "", errorMissingField
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if provider == "commento" && password == "" {
|
||||||
|
return "", errorMissingField
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := commenterGetByEmail(provider, email); err == nil {
|
||||||
|
return "", errorEmailAlreadyExists
|
||||||
|
}
|
||||||
|
|
||||||
commenterHex, err := randomHex(32)
|
commenterHex, err := randomHex(32)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", errorInternal
|
return "", errorInternal
|
||||||
}
|
}
|
||||||
|
|
||||||
|
passwordHash := []byte{}
|
||||||
|
if (password != "") {
|
||||||
|
passwordHash, err = bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
|
||||||
|
if err != nil {
|
||||||
|
logger.Errorf("cannot generate hash from password: %v\n", err)
|
||||||
|
return "", errorInternal
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
statement := `
|
statement := `
|
||||||
INSERT INTO
|
INSERT INTO
|
||||||
commenters (commenterHex, email, name, link, photo, provider, joinDate)
|
commenters (commenterHex, email, name, link, photo, provider, passwordHash, joinDate)
|
||||||
VALUES ($1, $2, $3, $4, $5, $6, $7 );
|
VALUES ($1, $2, $3, $4, $5, $6, $7, $8 );
|
||||||
`
|
`
|
||||||
_, err = db.Exec(statement, commenterHex, email, name, link, photo, provider, time.Now().UTC())
|
_, err = db.Exec(statement, commenterHex, email, name, link, photo, provider, string(passwordHash), time.Now().UTC())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
logger.Errorf("cannot insert commenter: %v", err)
|
||||||
return "", errorInternal
|
return "", errorInternal
|
||||||
}
|
}
|
||||||
|
|
||||||
return commenterHex, nil
|
return commenterHex, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func commenterNewHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
type request struct {
|
||||||
|
Email *string `json:"email"`
|
||||||
|
Name *string `json:"name"`
|
||||||
|
Website *string `json:"website"`
|
||||||
|
Password *string `json:"password"`
|
||||||
|
}
|
||||||
|
|
||||||
|
var x request
|
||||||
|
if err := unmarshalBody(r, &x); err != nil {
|
||||||
|
writeBody(w, response{"success": false, "message": err.Error()})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: add gravatar?
|
||||||
|
// TODO: email confirmation if provider = commento?
|
||||||
|
// TODO: email confirmation if provider = commento?
|
||||||
|
if _, err := commenterNew(*x.Email, *x.Name, *x.Website, "undefined", "commento", *x.Password); err != nil {
|
||||||
|
writeBody(w, response{"success": false, "message": err.Error()})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
writeBody(w, response{"success": true, "confirmEmail": smtpConfigured})
|
||||||
|
}
|
||||||
|
@ -7,7 +7,7 @@ import (
|
|||||||
func TestCommenterNewBasics(t *testing.T) {
|
func TestCommenterNewBasics(t *testing.T) {
|
||||||
failTestOnError(t, setupTestEnv())
|
failTestOnError(t, setupTestEnv())
|
||||||
|
|
||||||
if _, err := commenterNew("test@example.com", "Test", "undefined", "https://example.com/photo.jpg", "google"); err != nil {
|
if _, err := commenterNew("test@example.com", "Test", "undefined", "https://example.com/photo.jpg", "google", ""); err != nil {
|
||||||
t.Errorf("unexpected error creating new commenter: %v", err)
|
t.Errorf("unexpected error creating new commenter: %v", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -16,13 +16,22 @@ func TestCommenterNewBasics(t *testing.T) {
|
|||||||
func TestCommenterNewEmpty(t *testing.T) {
|
func TestCommenterNewEmpty(t *testing.T) {
|
||||||
failTestOnError(t, setupTestEnv())
|
failTestOnError(t, setupTestEnv())
|
||||||
|
|
||||||
if _, err := commenterNew("", "Test", "undefined", "https://example.com/photo.jpg", "google"); err == nil {
|
if _, err := commenterNew("", "Test", "undefined", "https://example.com/photo.jpg", "google", ""); err == nil {
|
||||||
t.Errorf("expected error not found creating new commenter with empty email")
|
t.Errorf("expected error not found creating new commenter with empty email")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err := commenterNew("", "", "", "", ""); err == nil {
|
if _, err := commenterNew("", "", "", "", "", ""); err == nil {
|
||||||
t.Errorf("expected error not found creating new commenter with empty everything")
|
t.Errorf("expected error not found creating new commenter with empty everything")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestCommenterNewCommento(t *testing.T) {
|
||||||
|
failTestOnError(t, setupTestEnv())
|
||||||
|
|
||||||
|
if _, err := commenterNew("test@example.com", "Test", "undefined", "", "commento", ""); err == nil {
|
||||||
|
t.Errorf("expected error not found creating new commento account with empty password")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -7,7 +7,7 @@ import (
|
|||||||
func TestCommenterSessionGetBasics(t *testing.T) {
|
func TestCommenterSessionGetBasics(t *testing.T) {
|
||||||
failTestOnError(t, setupTestEnv())
|
failTestOnError(t, setupTestEnv())
|
||||||
|
|
||||||
commenterHex, _ := commenterNew("test@example.com", "Test", "undefined", "https://example.com/photo.jpg", "google")
|
commenterHex, _ := commenterNew("test@example.com", "Test", "undefined", "https://example.com/photo.jpg", "google", "")
|
||||||
|
|
||||||
session, _ := commenterSessionNew()
|
session, _ := commenterSessionNew()
|
||||||
|
|
||||||
|
@ -29,8 +29,8 @@ func parseConfig() error {
|
|||||||
"SMTP_PORT": "",
|
"SMTP_PORT": "",
|
||||||
"SMTP_FROM_ADDRESS": "",
|
"SMTP_FROM_ADDRESS": "",
|
||||||
|
|
||||||
"OAUTH_GOOGLE_KEY": "",
|
"GOOGLE_KEY": "",
|
||||||
"OAUTH_GOOGLE_SECRET": "",
|
"GOOGLE_SECRET": "",
|
||||||
}
|
}
|
||||||
|
|
||||||
for key, value := range defaults {
|
for key, value := range defaults {
|
||||||
|
@ -2,7 +2,11 @@ package main
|
|||||||
|
|
||||||
import ()
|
import ()
|
||||||
|
|
||||||
|
var configuredOauths []string
|
||||||
|
|
||||||
func oauthConfigure() error {
|
func oauthConfigure() error {
|
||||||
|
configuredOauths = []string{}
|
||||||
|
|
||||||
if err := googleOauthConfigure(); err != nil {
|
if err := googleOauthConfigure(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -37,5 +37,7 @@ func googleOauthConfigure() error {
|
|||||||
Endpoint: google.Endpoint,
|
Endpoint: google.Endpoint,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
configuredOauths = append(configuredOauths, "google");
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -64,7 +64,7 @@ func googleCallbackHandler(w http.ResponseWriter, r *http.Request) {
|
|||||||
link = "undefined"
|
link = "undefined"
|
||||||
}
|
}
|
||||||
|
|
||||||
commenterHex, err = commenterNew(email, user["name"].(string), link, user["picture"].(string), "google")
|
commenterHex, err = commenterNew(email, user["name"].(string), link, user["picture"].(string), "google", "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Fprintf(w, "Error: %s", err.Error())
|
fmt.Fprintf(w, "Error: %s", err.Error())
|
||||||
return
|
return
|
||||||
|
@ -21,6 +21,8 @@ func initAPIRouter(router *mux.Router) error {
|
|||||||
router.HandleFunc("/api/domain/statistics", domainStatisticsHandler).Methods("POST")
|
router.HandleFunc("/api/domain/statistics", domainStatisticsHandler).Methods("POST")
|
||||||
|
|
||||||
router.HandleFunc("/api/commenter/session/new", commenterSessionNewHandler).Methods("GET")
|
router.HandleFunc("/api/commenter/session/new", commenterSessionNewHandler).Methods("GET")
|
||||||
|
router.HandleFunc("/api/commenter/new", commenterNewHandler).Methods("POST")
|
||||||
|
router.HandleFunc("/api/commenter/login", commenterLoginHandler).Methods("POST")
|
||||||
router.HandleFunc("/api/commenter/self", commenterSelfHandler).Methods("POST")
|
router.HandleFunc("/api/commenter/self", commenterSelfHandler).Methods("POST")
|
||||||
|
|
||||||
router.HandleFunc("/api/oauth/google/redirect", googleRedirectHandler).Methods("GET")
|
router.HandleFunc("/api/oauth/google/redirect", googleRedirectHandler).Methods("GET")
|
||||||
|
2
db/20180610215858-commenter-password.sql
Normal file
2
db/20180610215858-commenter-password.sql
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
ALTER TABLE commenters
|
||||||
|
ADD passwordHash TEXT NOT NULL DEFAULT '';
|
@ -153,10 +153,10 @@
|
|||||||
<div class="pitch">
|
<div class="pitch">
|
||||||
Moderators have the power to approve and delete comments. To make someone a moderator, add their email address down below. Once added, shiny new moderation buttons will appear on each comment for that person on each page on this domain.
|
Moderators have the power to approve and delete comments. To make someone a moderator, add their email address down below. Once added, shiny new moderation buttons will appear on each comment for that person on each page on this domain.
|
||||||
</div>
|
</div>
|
||||||
<div class="email-container">
|
<div class="commento-email-container">
|
||||||
<div class="email">
|
<div class="commento-email">
|
||||||
<input class="input" type="text" id="new-mod" placeholder="Email">
|
<input class="commento-input" type="text" id="new-mod" placeholder="Email">
|
||||||
<button id="new-mod-button" class="email-button" onclick="window.moderatorNewHandler()">Add moderator</button>
|
<button id="new-mod-button" class="commento-email-button" onclick="window.moderatorNewHandler()">Add moderator</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="mod-emails-container">
|
<div class="mod-emails-container">
|
||||||
@ -244,10 +244,10 @@
|
|||||||
|
|
||||||
<br><br>
|
<br><br>
|
||||||
|
|
||||||
<div class="email-container">
|
<div class="commento-email-container">
|
||||||
<div class="email">
|
<div class="commento-email">
|
||||||
<input class="input" type="text" id="new-mod" placeholder="https://media.disqus.com/uploads/...">
|
<input class="commento-input" type="text" id="new-mod" placeholder="https://media.disqus.com/uploads/...">
|
||||||
<button class="email-button">Import</button>
|
<button class="commento-email-button">Import</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="subtext-container">
|
<div class="subtext-container">
|
||||||
|
@ -11,6 +11,43 @@
|
|||||||
// override that.
|
// override that.
|
||||||
|
|
||||||
|
|
||||||
|
var ID_ROOT = "commento";
|
||||||
|
var ID_MAIN_AREA = "commento-main-area";
|
||||||
|
var ID_LOGIN_BOX_CONTAINER = "commento-login-box-container";
|
||||||
|
var ID_LOGIN_BOX = "commento-login-box";
|
||||||
|
var ID_LOGIN_BOX_HEADER = "commento-login-box-header";
|
||||||
|
var ID_LOGIN_BOX_SUBTITLE = "commento-login-box-subtitle";
|
||||||
|
var ID_LOGIN_BOX_EMAIL_INPUT = "commento-login-box-email-input";
|
||||||
|
var ID_LOGIN_BOX_PASSWORD_INPUT = "commento-login-box-password-input";
|
||||||
|
var ID_LOGIN_BOX_NAME_INPUT = "commento-login-box-name-input";
|
||||||
|
var ID_LOGIN_BOX_WEBSITE_INPUT = "commento-login-box-website-input";
|
||||||
|
var ID_LOGIN_BOX_EMAIL_BUTTON = "commento-login-box-email-button";
|
||||||
|
var ID_LOGIN_BOX_LOGIN_LINK_CONTAINER = "commento-login-box-login-link-container";
|
||||||
|
var ID_LOGIN_BOX_LOGIN_LINK = "commento-login-box-login-link";
|
||||||
|
var ID_LOGIN_BOX_HR = "commento-login-box-hr";
|
||||||
|
var ID_LOGIN_BOX_OAUTH_PRETEXT = "commento-login-box-oauth-pretext";
|
||||||
|
var ID_LOGIN_BOX_OAUTH_BUTTONS_CONTAINER = "commento-login-box-oauth-buttons-container";
|
||||||
|
var ID_ERROR = "commento-error";
|
||||||
|
var ID_COMMENTS_AREA = "commento-comments-area";
|
||||||
|
var ID_SUPER_CONTAINER = "commento-textarea-super-container-";
|
||||||
|
var ID_TEXTAREA_CONTAINER = "commento-textarea-container-";
|
||||||
|
var ID_TEXTAREA = "commento-textarea-";
|
||||||
|
var ID_CARD = "commento-comment-card-";
|
||||||
|
var ID_BODY = "commento-comment-body-";
|
||||||
|
var ID_SUBTITLE = "commento-comment-subtitle-";
|
||||||
|
var ID_SCORE = "commento-comment-score-";
|
||||||
|
var ID_OPTIONS = "commento-comment-options-";
|
||||||
|
var ID_EDIT = "commento-comment-edit-";
|
||||||
|
var ID_REPLY = "commento-comment-reply-";
|
||||||
|
var ID_COLLAPSE = "commento-comment-collapse-";
|
||||||
|
var ID_UPVOTE = "commento-comment-upvote-";
|
||||||
|
var ID_DOWNVOTE = "commento-comment-downvote-";
|
||||||
|
var ID_APPROVE = "commento-comment-approve-";
|
||||||
|
var ID_REMOVE = "commento-comment-remove-";
|
||||||
|
var ID_CONTENTS = "commento-comment-contents-";
|
||||||
|
var ID_SUBMIT_BUTTON = "commento-submit-button-";
|
||||||
|
|
||||||
|
|
||||||
var origin = global.commento_origin;
|
var origin = global.commento_origin;
|
||||||
var cdn = global.commento_cdn;
|
var cdn = global.commento_cdn;
|
||||||
var root = null;
|
var root = null;
|
||||||
@ -24,6 +61,8 @@
|
|||||||
var chosenAnonymous = false;
|
var chosenAnonymous = false;
|
||||||
var shownSubmitButton = {"root": false};
|
var shownSubmitButton = {"root": false};
|
||||||
var shownReply = {};
|
var shownReply = {};
|
||||||
|
var configuredOauths = [];
|
||||||
|
var loginBoxType = "signup";
|
||||||
|
|
||||||
|
|
||||||
function $(id) {
|
function $(id) {
|
||||||
@ -169,27 +208,37 @@
|
|||||||
var loggedContainer = create("div");
|
var loggedContainer = create("div");
|
||||||
var loggedInAs = create("div");
|
var loggedInAs = create("div");
|
||||||
var name = create("a");
|
var name = create("a");
|
||||||
var photo = create("img");
|
var avatar;
|
||||||
var logout = create("div");
|
var logout = create("div");
|
||||||
|
var color = colorGet(resp.commenter.name);
|
||||||
|
|
||||||
classAdd(loggedContainer, "logged-container");
|
classAdd(loggedContainer, "logged-container");
|
||||||
classAdd(loggedInAs, "logged-in-as");
|
classAdd(loggedInAs, "logged-in-as");
|
||||||
classAdd(name, "name");
|
classAdd(name, "name");
|
||||||
classAdd(photo, "photo");
|
|
||||||
classAdd(logout, "logout");
|
classAdd(logout, "logout");
|
||||||
|
|
||||||
name.innerText = resp.commenter.name;
|
name.innerText = resp.commenter.name;
|
||||||
logout.innerText = "Logout";
|
logout.innerText = "Logout";
|
||||||
|
|
||||||
attr(name, "href", resp.commenter.link);
|
|
||||||
if (resp.commenter.provider == "google") {
|
|
||||||
attr(photo, "src", resp.commenter.photo + "?sz=50");
|
|
||||||
} else {
|
|
||||||
attr(photo, "src", resp.commenter.photo);
|
|
||||||
}
|
|
||||||
attr(logout, "onclick", "logout()");
|
attr(logout, "onclick", "logout()");
|
||||||
|
attr(name, "href", resp.commenter.link);
|
||||||
|
if (resp.commenter.photo == "undefined") {
|
||||||
|
avatar = create("div");
|
||||||
|
avatar.style["background"] = color;
|
||||||
|
avatar.style["boxShadow"] = "0px 0px 0px 2px " + color;
|
||||||
|
avatar.innerHTML = resp.commenter.name[0].toUpperCase();
|
||||||
|
classAdd(avatar, "avatar");
|
||||||
|
} else {
|
||||||
|
avatar = create("img");
|
||||||
|
if (resp.commenter.provider == "google") {
|
||||||
|
attr(avatar, "src", resp.commenter.photo + "?sz=50");
|
||||||
|
} else {
|
||||||
|
attr(avatar, "src", resp.commenter.photo);
|
||||||
|
}
|
||||||
|
classAdd(avatar, "avatar-img");
|
||||||
|
}
|
||||||
|
|
||||||
append(loggedInAs, photo);
|
append(loggedInAs, avatar);
|
||||||
append(loggedInAs, name);
|
append(loggedInAs, name);
|
||||||
append(loggedContainer, loggedInAs);
|
append(loggedContainer, loggedInAs);
|
||||||
append(loggedContainer, logout);
|
append(loggedContainer, logout);
|
||||||
@ -280,6 +329,10 @@
|
|||||||
isFrozen = resp.isFrozen;
|
isFrozen = resp.isFrozen;
|
||||||
comments = resp.comments;
|
comments = resp.comments;
|
||||||
commenters = resp.commenters;
|
commenters = resp.commenters;
|
||||||
|
configuredOauths = resp.configuredOauths;
|
||||||
|
|
||||||
|
if (!resp.requireModeration)
|
||||||
|
configuredOauths.push("anonymous");
|
||||||
|
|
||||||
cssLoad(cdn + "/css/commento.css");
|
cssLoad(cdn + "/css/commento.css");
|
||||||
|
|
||||||
@ -335,43 +388,25 @@
|
|||||||
|
|
||||||
if (!isAuthenticated && !chosenAnonymous) {
|
if (!isAuthenticated && !chosenAnonymous) {
|
||||||
var buttonsContainer = create("div");
|
var buttonsContainer = create("div");
|
||||||
|
var createButton = create("div");
|
||||||
|
|
||||||
if (!isMobile()) {
|
classAdd(buttonsContainer, "create-container");
|
||||||
classAdd(buttonsContainer, "buttons-container");
|
|
||||||
classAdd(textarea, "blurred-textarea");
|
|
||||||
} else {
|
|
||||||
classAdd(textarea, "hidden");
|
|
||||||
classAdd(buttonsContainer, "mobile-buttons-container");
|
|
||||||
classAdd(buttonsContainer, "opaque");
|
|
||||||
}
|
|
||||||
|
|
||||||
var oauths = ["google"];
|
classAdd(createButton, "button");
|
||||||
if (!requireIdentification)
|
classAdd(createButton, "create-button");
|
||||||
oauths.push("anonymous");
|
|
||||||
|
|
||||||
for (var i = 0; i < oauths.length; i++) {
|
|
||||||
var oauthButton = create("button");
|
|
||||||
|
|
||||||
classAdd(oauthButton, "button");
|
|
||||||
classAdd(oauthButton, oauths[i] + "-button");
|
|
||||||
|
|
||||||
if (isMobile())
|
|
||||||
classAdd(oauthButton, "opaque");
|
|
||||||
|
|
||||||
attr(oauthButton, "onclick", "commentoAuth('" + oauths[i] + "', '" + id + "')");
|
|
||||||
|
|
||||||
oauthButton.innerText = oauths[i][0].toUpperCase() + oauths[i].slice(1);
|
|
||||||
|
|
||||||
append(buttonsContainer, oauthButton);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
attr(createButton, "onclick", "loginBoxShow()");
|
||||||
attr(textarea, "disabled", true);
|
attr(textarea, "disabled", true);
|
||||||
|
|
||||||
|
createButton.innerText = "Create an Account";
|
||||||
|
|
||||||
|
append(buttonsContainer, createButton);
|
||||||
append(textareaContainer, buttonsContainer);
|
append(textareaContainer, buttonsContainer);
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
attr(textarea, "placeholder", "Join the discussion!");
|
attr(textarea, "placeholder", "Join the discussion!");
|
||||||
attr(textarea, "onclick", "showSubmitButton('" + id + "')");
|
attr(textarea, "onclick", "showSubmitButton('" + id + "')");
|
||||||
|
}
|
||||||
|
|
||||||
textarea.oninput = autoExpander(textarea);
|
textarea.oninput = autoExpander(textarea);
|
||||||
|
|
||||||
@ -382,6 +417,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
function rootCreate(callback) {
|
function rootCreate(callback) {
|
||||||
|
var mainArea = $(ID_MAIN_AREA);
|
||||||
var commentsArea = create("div");
|
var commentsArea = create("div");
|
||||||
|
|
||||||
commentsArea.id = ID_COMMENTS_AREA;
|
commentsArea.id = ID_COMMENTS_AREA;
|
||||||
@ -390,8 +426,9 @@
|
|||||||
|
|
||||||
commentsArea.innerHTML = "";
|
commentsArea.innerHTML = "";
|
||||||
|
|
||||||
append(root, textareaCreate("root"));
|
append(mainArea, textareaCreate("root"));
|
||||||
append(root, commentsArea);
|
append(mainArea, commentsArea);
|
||||||
|
append(root, mainArea);
|
||||||
|
|
||||||
call(callback);
|
call(callback);
|
||||||
}
|
}
|
||||||
@ -439,7 +476,7 @@
|
|||||||
$(ID_COMMENTS_AREA).innerHTML = "";
|
$(ID_COMMENTS_AREA).innerHTML = "";
|
||||||
commentsRender();
|
commentsRender();
|
||||||
|
|
||||||
if (requireModeration && !isModerator) {
|
if (!resp.approved) {
|
||||||
if (id == "root") {
|
if (id == "root") {
|
||||||
var body = $(ID_SUPER_CONTAINER + id);
|
var body = $(ID_SUPER_CONTAINER + id);
|
||||||
prepend(body, messageCreate("Your comment is under moderation."));
|
prepend(body, messageCreate("Your comment is under moderation."));
|
||||||
@ -511,26 +548,6 @@
|
|||||||
return score + " point";
|
return score + " point";
|
||||||
}
|
}
|
||||||
|
|
||||||
var ID_ERROR = "commento-error";
|
|
||||||
var ID_COMMENTS_AREA = "commento-comments-area";
|
|
||||||
var ID_SUPER_CONTAINER = "commento-textarea-super-container-";
|
|
||||||
var ID_TEXTAREA_CONTAINER = "commento-textarea-container-";
|
|
||||||
var ID_TEXTAREA = "commento-textarea-";
|
|
||||||
var ID_CARD = "commento-comment-card-";
|
|
||||||
var ID_BODY = "commento-comment-body-";
|
|
||||||
var ID_SUBTITLE = "commento-comment-subtitle-";
|
|
||||||
var ID_SCORE = "commento-comment-score-";
|
|
||||||
var ID_OPTIONS = "commento-comment-options-";
|
|
||||||
var ID_EDIT = "commento-comment-edit-";
|
|
||||||
var ID_REPLY = "commento-comment-reply-";
|
|
||||||
var ID_COLLAPSE = "commento-comment-collapse-";
|
|
||||||
var ID_UPVOTE = "commento-comment-upvote-";
|
|
||||||
var ID_DOWNVOTE = "commento-comment-downvote-";
|
|
||||||
var ID_APPROVE = "commento-comment-approve-";
|
|
||||||
var ID_REMOVE = "commento-comment-remove-";
|
|
||||||
var ID_CONTENTS = "commento-comment-contents-";
|
|
||||||
var ID_SUBMIT_BUTTON = "commento-submit-button-";
|
|
||||||
|
|
||||||
function commentsRecurse(parentMap, parentHex) {
|
function commentsRecurse(parentMap, parentHex) {
|
||||||
var cur = parentMap[parentHex];
|
var cur = parentMap[parentHex];
|
||||||
if (!cur || !cur.length) {
|
if (!cur || !cur.length) {
|
||||||
@ -639,7 +656,6 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
attr(edit, "onclick", "startEdit('" + comment.commentHex + "')");
|
attr(edit, "onclick", "startEdit('" + comment.commentHex + "')");
|
||||||
attr(reply, "onclick", "replyShow('" + comment.commentHex + "')");
|
|
||||||
attr(collapse, "onclick", "commentCollapse('" + comment.commentHex + "')");
|
attr(collapse, "onclick", "commentCollapse('" + comment.commentHex + "')");
|
||||||
attr(approve, "onclick", "commentApprove('" + comment.commentHex + "')");
|
attr(approve, "onclick", "commentApprove('" + comment.commentHex + "')");
|
||||||
attr(remove, "onclick", "commentDelete('" + comment.commentHex + "')");
|
attr(remove, "onclick", "commentDelete('" + comment.commentHex + "')");
|
||||||
@ -657,9 +673,16 @@
|
|||||||
attr(upvote, "onclick", "vote('" + comment.commentHex + "', 0, 1)");
|
attr(upvote, "onclick", "vote('" + comment.commentHex + "', 0, 1)");
|
||||||
attr(downvote, "onclick", "vote('" + comment.commentHex + "', 0, -1)");
|
attr(downvote, "onclick", "vote('" + comment.commentHex + "', 0, -1)");
|
||||||
}
|
}
|
||||||
} else if (!chosenAnonymous) {
|
|
||||||
attr(upvote, "onclick", "replyShow('" + comment.commentHex + "')");
|
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
attr(upvote, "onclick", "loginBoxShow()");
|
||||||
|
attr(downvote, "onclick", "loginBoxShow()");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isAuthenticated || chosenAnonymous)
|
||||||
|
attr(reply, "onclick", "replyShow('" + comment.commentHex + "')");
|
||||||
|
else
|
||||||
|
attr(reply, "onclick", "loginBoxShow()");
|
||||||
|
|
||||||
if (isAuthenticated) {
|
if (isAuthenticated) {
|
||||||
if (isModerator) {
|
if (isModerator) {
|
||||||
@ -680,11 +703,9 @@
|
|||||||
if (false) // replace when edit is implemented
|
if (false) // replace when edit is implemented
|
||||||
append(options, edit);
|
append(options, edit);
|
||||||
|
|
||||||
if (isAuthenticated) {
|
|
||||||
append(options, upvote);
|
append(options, upvote);
|
||||||
append(options, downvote);
|
append(options, downvote);
|
||||||
append(options, reply);
|
append(options, reply);
|
||||||
}
|
|
||||||
|
|
||||||
if (isModerator) {
|
if (isModerator) {
|
||||||
if (comment.state == "unapproved")
|
if (comment.state == "unapproved")
|
||||||
@ -906,16 +927,11 @@
|
|||||||
append(el, submit);
|
append(el, submit);
|
||||||
}
|
}
|
||||||
|
|
||||||
global.commentoAuth = function(provider, id) {
|
global.commentoAuth = function(provider) {
|
||||||
if (provider == "anonymous") {
|
if (provider == "anonymous") {
|
||||||
cookieSet("session", "anonymous");
|
cookieSet("session", "anonymous");
|
||||||
chosenAnonymous = true;
|
chosenAnonymous = true;
|
||||||
refreshAll(function() {
|
refreshAll();
|
||||||
if (id != "root")
|
|
||||||
global.replyShow(id);
|
|
||||||
$(ID_TEXTAREA + id).click();
|
|
||||||
$(ID_TEXTAREA + id).focus();
|
|
||||||
});
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -933,12 +949,7 @@
|
|||||||
|
|
||||||
var interval = setInterval(function() {
|
var interval = setInterval(function() {
|
||||||
if (popup.closed) {
|
if (popup.closed) {
|
||||||
refreshAll(function() {
|
refreshAll();
|
||||||
if (id != "root")
|
|
||||||
global.replyShow(id);
|
|
||||||
$(ID_TEXTAREA + id).click();
|
|
||||||
$(ID_TEXTAREA + id).focus();
|
|
||||||
});
|
|
||||||
clearInterval(interval);
|
clearInterval(interval);
|
||||||
}
|
}
|
||||||
}, 250);
|
}, 250);
|
||||||
@ -946,17 +957,305 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
function refreshAll(callback) {
|
function refreshAll(callback) {
|
||||||
$("commento").innerHTML = "";
|
$(ID_ROOT).innerHTML = "";
|
||||||
shownSubmitButton = {"root": false};
|
shownSubmitButton = {"root": false};
|
||||||
shownReply = {};
|
shownReply = {};
|
||||||
main(callback);
|
main(callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function loginBoxCreate() {
|
||||||
|
var loginBoxContainer = create("div");
|
||||||
|
|
||||||
|
loginBoxContainer.id = ID_LOGIN_BOX_CONTAINER;
|
||||||
|
|
||||||
|
append(root, loginBoxContainer);
|
||||||
|
}
|
||||||
|
|
||||||
|
global.signupRender = function() {
|
||||||
|
var loginBoxContainer = $(ID_LOGIN_BOX_CONTAINER);
|
||||||
|
var loginBox = create("div");
|
||||||
|
var header = create("div");
|
||||||
|
var subtitle = create("div");
|
||||||
|
var emailContainer = create("div");
|
||||||
|
var email = create("div");
|
||||||
|
var emailInput = create("input");
|
||||||
|
var emailButton = create("button");
|
||||||
|
var loginLinkContainer = create("div");
|
||||||
|
var loginLink = create("a");
|
||||||
|
var hr = create("hr");
|
||||||
|
var oauthPretext = create("div");
|
||||||
|
var oauthButtonsContainer = create("div");
|
||||||
|
var oauthButtons = create("div");
|
||||||
|
var close = create("div");
|
||||||
|
|
||||||
|
loginBox.id = ID_LOGIN_BOX;
|
||||||
|
header.id = ID_LOGIN_BOX_HEADER;
|
||||||
|
subtitle.id = ID_LOGIN_BOX_SUBTITLE;
|
||||||
|
emailInput.id = ID_LOGIN_BOX_EMAIL_INPUT;
|
||||||
|
emailButton.id = ID_LOGIN_BOX_EMAIL_BUTTON;
|
||||||
|
loginLink.id = ID_LOGIN_BOX_LOGIN_LINK;
|
||||||
|
loginLinkContainer.id = ID_LOGIN_BOX_LOGIN_LINK_CONTAINER;
|
||||||
|
hr.id = ID_LOGIN_BOX_HR;
|
||||||
|
oauthPretext.id = ID_LOGIN_BOX_OAUTH_PRETEXT;
|
||||||
|
oauthButtonsContainer.id = ID_LOGIN_BOX_OAUTH_BUTTONS_CONTAINER;
|
||||||
|
|
||||||
|
header.innerText = "Create an account to join the discussion!";
|
||||||
|
|
||||||
|
classAdd(loginBoxContainer, "login-box-container");
|
||||||
|
classAdd(loginBox, "login-box");
|
||||||
|
classAdd(header, "login-box-header");
|
||||||
|
classAdd(subtitle, "login-box-subtitle");
|
||||||
|
classAdd(emailContainer, "email-container");
|
||||||
|
classAdd(email, "email");
|
||||||
|
classAdd(emailInput, "input");
|
||||||
|
classAdd(emailButton, "email-button");
|
||||||
|
classAdd(loginLinkContainer, "login-link-container");
|
||||||
|
classAdd(loginLink, "login-link");
|
||||||
|
classAdd(oauthPretext, "login-box-subtitle");
|
||||||
|
classAdd(oauthButtonsContainer, "oauth-buttons-container");
|
||||||
|
classAdd(oauthButtons, "oauth-buttons");
|
||||||
|
classAdd(close, "login-box-close");
|
||||||
|
|
||||||
|
emailButton.innerText = "Continue";
|
||||||
|
loginLink.innerText = "Already have an account? Log in.";
|
||||||
|
subtitle.innerText = "Sign up with your email to vote and comment.";
|
||||||
|
oauthPretext.innerText = "Or proceed with social login.";
|
||||||
|
|
||||||
|
attr(loginBoxContainer, "style", "display: none; opacity: 0;");
|
||||||
|
attr(emailInput, "name", "email");
|
||||||
|
attr(emailInput, "placeholder", "Email address");
|
||||||
|
attr(emailInput, "type", "text");
|
||||||
|
attr(emailButton, "onclick", "passwordAsk()");
|
||||||
|
attr(loginLink, "onclick", "loginSwitch()");
|
||||||
|
attr(close, "onclick", "loginBoxClose()");
|
||||||
|
|
||||||
|
for (var i = 0; i < configuredOauths.length; i++) {
|
||||||
|
var button = create("button");
|
||||||
|
|
||||||
|
classAdd(button, "button");
|
||||||
|
classAdd(button, configuredOauths[i] + "-button");
|
||||||
|
|
||||||
|
button.innerText = configuredOauths[i];
|
||||||
|
|
||||||
|
attr(button, "onclick", "commentoAuth('" + configuredOauths[i] + "')");
|
||||||
|
|
||||||
|
append(oauthButtons, button);
|
||||||
|
}
|
||||||
|
|
||||||
|
append(loginBox, header);
|
||||||
|
append(loginBox, subtitle);
|
||||||
|
|
||||||
|
append(email, emailInput);
|
||||||
|
append(email, emailButton);
|
||||||
|
append(emailContainer, email);
|
||||||
|
append(loginBox, emailContainer);
|
||||||
|
|
||||||
|
append(loginLinkContainer, loginLink);
|
||||||
|
append(loginBox, loginLinkContainer);
|
||||||
|
|
||||||
|
append(loginBox, hr);
|
||||||
|
|
||||||
|
if (configuredOauths.length > 0) {
|
||||||
|
append(loginBox, oauthPretext);
|
||||||
|
append(oauthButtonsContainer, oauthButtons);
|
||||||
|
append(loginBox, oauthButtonsContainer);
|
||||||
|
}
|
||||||
|
|
||||||
|
append(loginBox, close);
|
||||||
|
|
||||||
|
loginBoxType = "signup";
|
||||||
|
loginBoxContainer.innerHTML = "";
|
||||||
|
append(loginBoxContainer, loginBox);
|
||||||
|
}
|
||||||
|
|
||||||
|
global.loginSwitch = function() {
|
||||||
|
var header = $(ID_LOGIN_BOX_HEADER);
|
||||||
|
var subtitle = $(ID_LOGIN_BOX_SUBTITLE);
|
||||||
|
var loginLink = $(ID_LOGIN_BOX_LOGIN_LINK);
|
||||||
|
var hr = $(ID_LOGIN_BOX_HR);
|
||||||
|
var oauthButtonsContainer = $(ID_LOGIN_BOX_OAUTH_BUTTONS_CONTAINER);
|
||||||
|
var oauthPretext = $(ID_LOGIN_BOX_OAUTH_PRETEXT);
|
||||||
|
|
||||||
|
header.innerText = "Login to continue";
|
||||||
|
loginLink.innerText = "Don't have an account? Sign up.";
|
||||||
|
subtitle.innerText = "Enter your email address to start with.";
|
||||||
|
|
||||||
|
attr(loginLink, "onclick", "signupSwitch()");
|
||||||
|
|
||||||
|
loginBoxType = "login";
|
||||||
|
|
||||||
|
remove(hr);
|
||||||
|
remove(oauthPretext);
|
||||||
|
remove(oauthButtonsContainer);
|
||||||
|
}
|
||||||
|
|
||||||
|
global.signupSwitch = function() {
|
||||||
|
loginBoxClose();
|
||||||
|
loginBoxShow();
|
||||||
|
}
|
||||||
|
|
||||||
|
function loginUP(username, password) {
|
||||||
|
var json = {
|
||||||
|
email: username,
|
||||||
|
password: password,
|
||||||
|
};
|
||||||
|
|
||||||
|
post(origin + "/api/commenter/login", json, function(resp) {
|
||||||
|
if (!resp.success) {
|
||||||
|
loginBoxClose();
|
||||||
|
errorShow(resp.message);
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
cookieSet("session", resp.session);
|
||||||
|
refreshAll();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
global.login = function() {
|
||||||
|
var email = $(ID_LOGIN_BOX_EMAIL_INPUT);
|
||||||
|
var password = $(ID_LOGIN_BOX_PASSWORD_INPUT);
|
||||||
|
|
||||||
|
loginUP(email.value, password.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
global.signup = function() {
|
||||||
|
var email = $(ID_LOGIN_BOX_EMAIL_INPUT);
|
||||||
|
var name = $(ID_LOGIN_BOX_NAME_INPUT);
|
||||||
|
var website = $(ID_LOGIN_BOX_WEBSITE_INPUT);
|
||||||
|
var password = $(ID_LOGIN_BOX_PASSWORD_INPUT);
|
||||||
|
|
||||||
|
var json = {
|
||||||
|
email: email.value,
|
||||||
|
name: name.value,
|
||||||
|
website: website.value,
|
||||||
|
password: password.value,
|
||||||
|
};
|
||||||
|
|
||||||
|
post(origin + "/api/commenter/new", json, function(resp) {
|
||||||
|
if (!resp.success) {
|
||||||
|
loginBoxClose();
|
||||||
|
errorShow(resp.message);
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
loginUP(email.value, password.value);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
global.passwordAsk = function() {
|
||||||
|
var loginBox = $(ID_LOGIN_BOX);
|
||||||
|
var subtitle = $(ID_LOGIN_BOX_SUBTITLE);
|
||||||
|
var emailInput = $(ID_LOGIN_BOX_EMAIL_INPUT);
|
||||||
|
var emailButton = $(ID_LOGIN_BOX_EMAIL_BUTTON);
|
||||||
|
var loginLinkContainer = $(ID_LOGIN_BOX_LOGIN_LINK_CONTAINER);
|
||||||
|
var hr = $(ID_LOGIN_BOX_HR);
|
||||||
|
var oauthButtonsContainer = $(ID_LOGIN_BOX_OAUTH_BUTTONS_CONTAINER);
|
||||||
|
var oauthPretext = $(ID_LOGIN_BOX_OAUTH_PRETEXT);
|
||||||
|
|
||||||
|
remove(emailButton);
|
||||||
|
remove(loginLinkContainer);
|
||||||
|
if (loginBoxType == "signup") {
|
||||||
|
remove(hr);
|
||||||
|
remove(oauthPretext);
|
||||||
|
remove(oauthButtonsContainer);
|
||||||
|
}
|
||||||
|
|
||||||
|
var order, id, type, placeholder;
|
||||||
|
|
||||||
|
if (loginBoxType == "signup") {
|
||||||
|
var order = ["name", "website", "password"];
|
||||||
|
var id = [ID_LOGIN_BOX_NAME_INPUT, ID_LOGIN_BOX_WEBSITE_INPUT, ID_LOGIN_BOX_PASSWORD_INPUT];
|
||||||
|
var type = ["text", "text", "password"];
|
||||||
|
var placeholder = ["Real Name", "Website (Optional)", "Password"];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
var order = ["password"];
|
||||||
|
var id = [ID_LOGIN_BOX_PASSWORD_INPUT];
|
||||||
|
var type = ["password"];
|
||||||
|
var placeholder = ["Password"];
|
||||||
|
}
|
||||||
|
|
||||||
|
subtitle.innerText = "Finish the rest of your profile to complete."
|
||||||
|
|
||||||
|
for (var i = 0; i < order.length; i++) {
|
||||||
|
var fieldContainer = create("div");
|
||||||
|
var field = create("div");
|
||||||
|
var fieldInput = create("input");
|
||||||
|
|
||||||
|
fieldInput.id = id[i];
|
||||||
|
|
||||||
|
classAdd(fieldContainer, "email-container");
|
||||||
|
classAdd(field, "email");
|
||||||
|
classAdd(fieldInput, "input");
|
||||||
|
|
||||||
|
attr(fieldInput, "name", order[i]);
|
||||||
|
attr(fieldInput, "type", type[i]);
|
||||||
|
attr(fieldInput, "placeholder", placeholder[i]);
|
||||||
|
|
||||||
|
append(field, fieldInput);
|
||||||
|
append(fieldContainer, field);
|
||||||
|
|
||||||
|
if (order[i] == "password") {
|
||||||
|
var fieldButton = create("button");
|
||||||
|
classAdd(fieldButton, "email-button");
|
||||||
|
fieldButton.innerText = loginBoxType;
|
||||||
|
|
||||||
|
if (loginBoxType == "signup")
|
||||||
|
attr(fieldButton, "onclick", "signup()");
|
||||||
|
else
|
||||||
|
attr(fieldButton, "onclick", "login()");
|
||||||
|
|
||||||
|
append(field, fieldButton);
|
||||||
|
}
|
||||||
|
|
||||||
|
append(loginBox, fieldContainer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function mainAreaCreate() {
|
||||||
|
var mainArea = create("div");
|
||||||
|
|
||||||
|
mainArea.id = ID_MAIN_AREA;
|
||||||
|
|
||||||
|
classAdd(mainArea, "main-area");
|
||||||
|
|
||||||
|
append(root, mainArea);
|
||||||
|
}
|
||||||
|
|
||||||
|
global.loginBoxClose = function() {
|
||||||
|
var mainArea = $(ID_MAIN_AREA);
|
||||||
|
var loginBoxContainer = $(ID_LOGIN_BOX_CONTAINER);
|
||||||
|
|
||||||
|
classRemove(mainArea, "blurred");
|
||||||
|
|
||||||
|
attr(loginBoxContainer, "style", "display: none");
|
||||||
|
}
|
||||||
|
|
||||||
|
global.loginBoxShow = function() {
|
||||||
|
var mainArea = $(ID_MAIN_AREA);
|
||||||
|
var loginBoxContainer = $(ID_LOGIN_BOX_CONTAINER);
|
||||||
|
|
||||||
|
global.signupRender();
|
||||||
|
|
||||||
|
classAdd(mainArea, "blurred");
|
||||||
|
|
||||||
|
attr(loginBoxContainer, "style", "");
|
||||||
|
|
||||||
|
window.location.hash = ID_LOGIN_BOX_CONTAINER;
|
||||||
|
|
||||||
|
$(ID_LOGIN_BOX_EMAIL_INPUT).focus();
|
||||||
|
}
|
||||||
|
|
||||||
function main(callback) {
|
function main(callback) {
|
||||||
root = $("commento");
|
root = $(ID_ROOT);
|
||||||
|
|
||||||
|
loginBoxCreate();
|
||||||
|
|
||||||
errorElementCreate();
|
errorElementCreate();
|
||||||
|
|
||||||
|
mainAreaCreate();
|
||||||
|
|
||||||
selfGet(function() {
|
selfGet(function() {
|
||||||
commentsGet(function() {
|
commentsGet(function() {
|
||||||
rootCreate(function() {
|
rootCreate(function() {
|
||||||
|
@ -14,9 +14,9 @@ input[type=text]::placeholder {
|
|||||||
|
|
||||||
textarea::placeholder {
|
textarea::placeholder {
|
||||||
color: #aaa;
|
color: #aaa;
|
||||||
font-size: 22px;
|
font-size: 20px;
|
||||||
padding-top: 13px;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
|
line-height: 80px;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
@ -28,7 +28,7 @@ textarea {
|
|||||||
padding: 8px;
|
padding: 8px;
|
||||||
outline: none;
|
outline: none;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
min-height: 75px;
|
min-height: 100px;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -41,65 +41,42 @@ textarea {
|
|||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
||||||
&:hover {
|
|
||||||
.commento-button, .commento-buttons-container::before {
|
|
||||||
opacity: 1;
|
|
||||||
transform: translate(0px,-3px);
|
|
||||||
}
|
|
||||||
|
|
||||||
.commento-submit-button {
|
.commento-submit-button {
|
||||||
transform: none;
|
transform: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.commento-blurred-textarea {
|
|
||||||
opacity: .7;
|
|
||||||
transform: scale(.95);
|
|
||||||
filter: blur(4px);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@media only screen and (max-width: 550px) {
|
.commento-oauth-buttons-container {
|
||||||
.commento-buttons-container::before {
|
display: flex;
|
||||||
display: none;
|
justify-content: center;
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.commento-buttons-container {
|
.commento-oauth-buttons,
|
||||||
display: inline-block;
|
.commento-create-container {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
opacity: 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.commento-mobile-buttons-container::before,
|
.commento-oauth-buttons {
|
||||||
.commento-buttons-container::before {
|
display: contents;
|
||||||
content: "Authenticate with";
|
}
|
||||||
display: inline-flex;
|
|
||||||
|
.commento-create-container::before {
|
||||||
|
content: "Want to add to the discussion?";
|
||||||
|
display: block;
|
||||||
|
text-align: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
line-height: 24px;
|
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
padding: 6px;
|
padding: 6px;
|
||||||
color: $gray-8;
|
color: $gray-8;
|
||||||
transition: all 0.3s;
|
|
||||||
opacity: 0;
|
|
||||||
outline: none;
|
outline: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.commento-mobile-buttons-container::before {
|
|
||||||
content: "To join the discussion, authenticate with";;
|
|
||||||
display: block;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media only screen and (max-width: 550px) {
|
|
||||||
.commento-buttons-container::before {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.commento-button {
|
.commento-button {
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
@ -118,31 +95,25 @@ textarea {
|
|||||||
color: #fff;
|
color: #fff;
|
||||||
width: 100px;
|
width: 100px;
|
||||||
margin-left: 5px;
|
margin-left: 5px;
|
||||||
margin-left: 5px;
|
margin-right: 5px;
|
||||||
opacity: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.commento-opaque {
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.commento-opaque::before {
|
|
||||||
opacity: 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.commento-google-button {
|
.commento-google-button {
|
||||||
transition: all 0.3s;
|
|
||||||
background: #dd4b39;
|
background: #dd4b39;
|
||||||
|
text-transform: uppercase;
|
||||||
|
font-size: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.commento-github-button {
|
.commento-github-button {
|
||||||
transition: all 0.3s;
|
|
||||||
background: #000000;
|
background: #000000;
|
||||||
|
text-transform: uppercase;
|
||||||
|
font-size: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.commento-anonymous-button {
|
.commento-anonymous-button {
|
||||||
transition: all 0.3s;
|
|
||||||
background: #096fa6;
|
background: #096fa6;
|
||||||
|
text-transform: uppercase;
|
||||||
|
font-size: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.commento-blurred-textarea {
|
.commento-blurred-textarea {
|
||||||
@ -152,7 +123,6 @@ textarea {
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
transition: 0.3s all;
|
|
||||||
will-change: transform;
|
will-change: transform;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -160,7 +130,6 @@ textarea {
|
|||||||
.commento-delete-button,
|
.commento-delete-button,
|
||||||
.commento-submit-button {
|
.commento-submit-button {
|
||||||
margin-top: 10px;
|
margin-top: 10px;
|
||||||
opacity: 1;
|
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
width: -moz-fit-content;
|
width: -moz-fit-content;
|
||||||
width: -webkit-fit-content;
|
width: -webkit-fit-content;
|
||||||
@ -169,6 +138,11 @@ textarea {
|
|||||||
width: fit-content;
|
width: fit-content;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.commento-create-button {
|
||||||
|
width: 150px;
|
||||||
|
background: $pink-9;
|
||||||
|
}
|
||||||
|
|
||||||
.commento-submit-button {
|
.commento-submit-button {
|
||||||
float: right;
|
float: right;
|
||||||
background: $indigo-7;
|
background: $indigo-7;
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
text-align: left;
|
text-align: left;
|
||||||
margin-bottom: 16px;
|
margin-bottom: 16px;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
height: 38px;
|
||||||
|
|
||||||
.commento-logout {
|
.commento-logout {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
@ -23,15 +24,7 @@
|
|||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 6px;
|
top: 6px;
|
||||||
left: 64px;
|
left: 48px;
|
||||||
}
|
|
||||||
|
|
||||||
.commento-photo {
|
|
||||||
width: 32px;
|
|
||||||
height: 32px;
|
|
||||||
border-radius: 50%;
|
|
||||||
margin-left: 16px;
|
|
||||||
margin-right: 16px;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
92
frontend/sass/commento-login.scss
Normal file
92
frontend/sass/commento-login.scss
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
@import "colors-main.scss";
|
||||||
|
|
||||||
|
.commento-login-box-container {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
position: relative;
|
||||||
|
width: 100%;
|
||||||
|
height: 0px;
|
||||||
|
overflow: visible;
|
||||||
|
|
||||||
|
.commento-login-box {
|
||||||
|
width: 90%;
|
||||||
|
max-width: 500px;
|
||||||
|
min-height: 125px;
|
||||||
|
background: $gray-1;
|
||||||
|
box-shadow: 0 4px 6px rgba(50,50,93,.11),0 1px 3px rgba(0,0,0,.08);
|
||||||
|
border: 1px solid transparent;
|
||||||
|
border-radius: 3px;
|
||||||
|
z-index: 100;
|
||||||
|
position: absolute;
|
||||||
|
top: 8px;
|
||||||
|
padding: 16px;
|
||||||
|
opacity: 1;
|
||||||
|
transition: opacity 0.2s;
|
||||||
|
|
||||||
|
hr {
|
||||||
|
border: none;
|
||||||
|
background: $gray-2;
|
||||||
|
height: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.commento-login-box-header {
|
||||||
|
font-size: 20px;
|
||||||
|
font-weight: 200;
|
||||||
|
text-align: center;
|
||||||
|
color: $pink-8;
|
||||||
|
margin: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.commento-login-box-subtitle {
|
||||||
|
color: $gray-6;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 15px;
|
||||||
|
margin: 12px 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@import "email-main.scss";
|
||||||
|
|
||||||
|
.commento-login-link-container {
|
||||||
|
margin: 16px;
|
||||||
|
width: calc(100% - 32px);
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
|
.commento-login-link {
|
||||||
|
font-size: 15px;
|
||||||
|
font-weight: bold;
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.commento-login-box-close {
|
||||||
|
position: absolute;
|
||||||
|
right: 16px;
|
||||||
|
top: 16px;
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
opacity: 0.3;
|
||||||
|
}
|
||||||
|
|
||||||
|
.commento-login-box-close:hover {
|
||||||
|
opacity: 1;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.commento-login-box-close:before, .commento-login-box-close:after {
|
||||||
|
position: absolute;
|
||||||
|
left: 7px;
|
||||||
|
content: ' ';
|
||||||
|
height: 17px;
|
||||||
|
width: 2px;
|
||||||
|
background-color: $gray-7;
|
||||||
|
}
|
||||||
|
|
||||||
|
.commento-login-box-close:before {
|
||||||
|
transform: rotate(45deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.commento-login-box-close:after {
|
||||||
|
transform: rotate(-45deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,11 +1,14 @@
|
|||||||
|
@import url('https://fonts.googleapis.com/css?family=Source+Sans+Pro');
|
||||||
|
|
||||||
#commento {
|
#commento {
|
||||||
font-family: "Source Sans Pro", "Segoe UI", Roboto, "Helvetica Neue", sans-serif;
|
font-family: "Source Sans Pro", "Segoe UI", Roboto, "Helvetica Neue", sans-serif;
|
||||||
font-size: 14px;
|
font-size: 15px;
|
||||||
line-height: 1.5;
|
line-height: 1.5;
|
||||||
color: #50596c;
|
color: #50596c;
|
||||||
overflow-x: hidden;
|
overflow-x: hidden;
|
||||||
text-rendering: optimizeLegibility;
|
text-rendering: optimizeLegibility;
|
||||||
padding: 8px;
|
padding: 8px;
|
||||||
|
min-height: 350px;
|
||||||
|
|
||||||
@import "colors-main.scss";
|
@import "colors-main.scss";
|
||||||
@import "common-main.scss";
|
@import "common-main.scss";
|
||||||
@ -15,11 +18,20 @@
|
|||||||
@import "commento-input.scss";
|
@import "commento-input.scss";
|
||||||
@import "commento-logged.scss";
|
@import "commento-logged.scss";
|
||||||
@import "commento-buttons.scss";
|
@import "commento-buttons.scss";
|
||||||
|
@import "commento-login.scss";
|
||||||
|
|
||||||
.commento-hidden {
|
.commento-hidden {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.commento-blurred {
|
||||||
|
filter: blur(4px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.commento-main-area {
|
||||||
|
transition: filter 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
.commento-error-box {
|
.commento-error-box {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
@ -43,15 +55,6 @@
|
|||||||
background: $blue-1;
|
background: $blue-1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.commento-card {
|
|
||||||
padding: 12px 0px 0px 12px;
|
|
||||||
margin-top: 16px;
|
|
||||||
border-top: 1px solid #f0f0f0;
|
|
||||||
|
|
||||||
.commento-header {
|
|
||||||
padding-bottom: 12px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.commento-avatar {
|
.commento-avatar {
|
||||||
width: 34px;
|
width: 34px;
|
||||||
height: 34px;
|
height: 34px;
|
||||||
@ -78,6 +81,15 @@
|
|||||||
margin-right: 10px;
|
margin-right: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.commento-card {
|
||||||
|
padding: 12px 0px 0px 12px;
|
||||||
|
margin-top: 16px;
|
||||||
|
border-top: 1px solid #f0f0f0;
|
||||||
|
|
||||||
|
.commento-header {
|
||||||
|
padding-bottom: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
.commento-avatar::after {
|
.commento-avatar::after {
|
||||||
content:"";
|
content:"";
|
||||||
display:block;
|
display:block;
|
||||||
|
@ -105,60 +105,7 @@ body {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.email-container {
|
@import "email-main.scss";
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
width: 100%;
|
|
||||||
|
|
||||||
.email {
|
|
||||||
@extend .shadow;
|
|
||||||
border-radius: 4px;
|
|
||||||
background: $white;
|
|
||||||
width: 100%;
|
|
||||||
max-width: 400px;
|
|
||||||
|
|
||||||
.input {
|
|
||||||
height: 40px;
|
|
||||||
background: $white;
|
|
||||||
border: none;
|
|
||||||
outline: none;
|
|
||||||
padding: 5px;
|
|
||||||
padding-left: 10px;
|
|
||||||
width: 250px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.input::placeholder {
|
|
||||||
color: $gray-5;
|
|
||||||
}
|
|
||||||
|
|
||||||
.email-button {
|
|
||||||
height: 40px;
|
|
||||||
min-width: 110px;
|
|
||||||
float: right;
|
|
||||||
background: $white;
|
|
||||||
border: none;
|
|
||||||
outline: none;
|
|
||||||
padding: 0px 10px 0px 10px;
|
|
||||||
border-left: 1px solid $gray-1;
|
|
||||||
font-size: 12px;
|
|
||||||
text-transform: uppercase;
|
|
||||||
text-align: center;
|
|
||||||
font-weight: bold;
|
|
||||||
color: $blue-7;
|
|
||||||
cursor: pointer;
|
|
||||||
transition: all 0.2s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.email-button:hover {
|
|
||||||
color: $blue-6;
|
|
||||||
}
|
|
||||||
|
|
||||||
.email-button:disabled {
|
|
||||||
cursor: default;
|
|
||||||
color: $gray-6;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.mod-emails-container {
|
.mod-emails-container {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
58
frontend/sass/email-main.scss
Normal file
58
frontend/sass/email-main.scss
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
@import "colors-main.scss";
|
||||||
|
@import "common-main.scss";
|
||||||
|
|
||||||
|
.commento-email-container {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
width: 100%;
|
||||||
|
margin: 8px 0px;
|
||||||
|
|
||||||
|
.commento-email {
|
||||||
|
@extend .shadow;
|
||||||
|
border-radius: 4px;
|
||||||
|
background: $white;
|
||||||
|
width: 100%;
|
||||||
|
max-width: 400px;
|
||||||
|
|
||||||
|
.commento-input {
|
||||||
|
height: 40px;
|
||||||
|
background: $white;
|
||||||
|
border: none;
|
||||||
|
outline: none;
|
||||||
|
padding: 5px;
|
||||||
|
padding-left: 10px;
|
||||||
|
width: calc(100% - 120px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.commento-input::placeholder {
|
||||||
|
color: $gray-5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.commento-email-button {
|
||||||
|
height: 40px;
|
||||||
|
min-width: 110px;
|
||||||
|
float: right;
|
||||||
|
background: $white;
|
||||||
|
border: none;
|
||||||
|
outline: none;
|
||||||
|
padding: 0px 10px 0px 10px;
|
||||||
|
border-left: 1px solid $gray-1;
|
||||||
|
font-size: 12px;
|
||||||
|
text-transform: uppercase;
|
||||||
|
text-align: center;
|
||||||
|
font-weight: bold;
|
||||||
|
color: $blue-7;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.commento-email-button:hover {
|
||||||
|
color: $blue-6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.commento-email-button:disabled {
|
||||||
|
cursor: default;
|
||||||
|
color: $gray-6;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user