Browse Source

Merge pull request #2 from gogits/develop

Update Develop
Yixin Hao 9 years ago
parent
commit
50cd67cd4b

+ 3 - 2
cmd/web.go

@@ -272,8 +272,9 @@ func runWeb(ctx *cli.Context) {
 		m.Post("/email", bindIgnErr(auth.AddEmailForm{}), user.SettingsEmailPost)
 		m.Get("/password", user.SettingsPassword)
 		m.Post("/password", bindIgnErr(auth.ChangePasswordForm{}), user.SettingsPasswordPost)
-		m.Get("/ssh", user.SettingsSSHKeys)
-		m.Post("/ssh", bindIgnErr(auth.AddSSHKeyForm{}), user.SettingsSSHKeysPost)
+		m.Combo("/ssh").Get(user.SettingsSSHKeys).
+			Post(bindIgnErr(auth.AddSSHKeyForm{}), user.SettingsSSHKeysPost)
+		m.Post("/ssh/delete", user.DeleteSSHKey)
 		m.Get("/social", user.SettingsSocial)
 		m.Combo("/applications").Get(user.SettingsApplications).
 			Post(bindIgnErr(auth.NewAccessTokenForm{}), user.SettingsApplicationsPost)

+ 3 - 0
conf/locale/locale_en-US.ini

@@ -276,6 +276,9 @@ key_name = Key Name
 key_content = Content
 add_key_success = New SSH key '%s' has been added successfully!
 delete_key = Delete
+ssh_key_deletion = SSH Key Deletion
+ssh_key_deletion_desc = Delete this SSH key will remove all related accesses for your account. Do you want to continue?
+ssh_key_deletion_success = SSH key has been deleted successfully!
 add_on = Added on
 last_used = Last used on
 no_activity = No recent activity

+ 6 - 0
models/git_diff.go

@@ -169,6 +169,12 @@ func ParsePatch(pid int64, maxlines int, cmd *exec.Cmd, reader io.Reader) (*Diff
 			beg := len(DIFF_HEAD)
 			a := line[beg : (len(line)-beg)/2+beg]
 
+			// In case file name is surrounded by double quotes(it happens only in git-shell).
+			if a[0] == '"' {
+				a = a[1 : len(a)-1]
+				a = strings.Replace(a, `\"`, `"`, -1)
+			}
+
 			curFile = &DiffFile{
 				Name:     a[strings.Index(a, "/")+1:],
 				Index:    len(diff.Files) + 1,

+ 9 - 1
models/publickey.go

@@ -466,7 +466,15 @@ func deletePublicKey(e *xorm.Session, key *PublicKey) error {
 }
 
 // DeletePublicKey deletes SSH key information both in database and authorized_keys file.
-func DeletePublicKey(key *PublicKey) (err error) {
+func DeletePublicKey(id int64) (err error) {
+	key := &PublicKey{ID: id}
+	has, err := x.Id(key.ID).Get(key)
+	if err != nil {
+		return err
+	} else if !has {
+		return nil
+	}
+
 	sess := x.NewSession()
 	defer sessionRelease(sess)
 	if err = sess.Begin(); err != nil {

+ 7 - 0
models/repo.go

@@ -166,6 +166,13 @@ type Repository struct {
 	Updated time.Time `xorm:"UPDATED"`
 }
 
+func (repo *Repository) AfterSet(colName string, _ xorm.Cell) {
+	switch colName {
+	case "updated":
+		repo.Updated = regulateTimeZone(repo.Updated)
+	}
+}
+
 func (repo *Repository) getOwner(e Engine) (err error) {
 	if repo.Owner == nil {
 		repo.Owner, err = getUserByID(e, repo.OwnerID)

File diff suppressed because it is too large
+ 0 - 0
modules/bindata/bindata.go


+ 3 - 1
modules/git/repo_commit.go

@@ -275,9 +275,11 @@ func (repo *Repository) searchCommits(id sha1, keyword string) (*list.List, erro
 	return parsePrettyFormatLog(repo, stdout)
 }
 
+var CommitsRangeSize = 50
+
 func (repo *Repository) commitsByRange(id sha1, page int) (*list.List, error) {
 	stdout, stderr, err := com.ExecCmdDirBytes(repo.Path, "git", "log", id.String(),
-		"--skip="+com.ToStr((page-1)*50), "--max-count=50", prettyLogFormat)
+		"--skip="+com.ToStr((page-1)*CommitsRangeSize), "--max-count="+com.ToStr(CommitsRangeSize), prettyLogFormat)
 	if err != nil {
 		return nil, errors.New(string(stderr))
 	}

+ 7 - 0
modules/git/tree.go

@@ -71,6 +71,13 @@ func parseTreeData(tree *Tree, data []byte) ([]*TreeEntry, error) {
 
 		step = bytes.IndexByte(data[pos:], '\n')
 		entry.name = string(data[pos : pos+step])
+
+		// In case entry name is surrounded by double quotes(it happens only in git-shell).
+		if entry.name[0] == '"' {
+			entry.name = string(data[pos+1 : pos+step-1])
+			entry.name = strings.Replace(entry.name, `\"`, `"`, -1)
+		}
+
 		pos += step + 1
 		entries = append(entries, entry)
 	}

+ 30 - 0
modules/mailer/mailer.go

@@ -17,6 +17,33 @@ import (
 	"github.com/gogits/gogs/modules/setting"
 )
 
+type loginAuth struct {
+	username, password string
+}
+
+// SMTP AUTH LOGIN Auth Handler
+func LoginAuth(username, password string) smtp.Auth {
+	return &loginAuth{username, password}
+}
+
+func (a *loginAuth) Start(server *smtp.ServerInfo) (string, []byte, error) {
+	return "LOGIN", []byte{}, nil
+}
+
+func (a *loginAuth) Next(fromServer []byte, more bool) ([]byte, error) {
+	if more {
+		switch string(fromServer) {
+		case "Username:":
+			return []byte(a.username), nil
+		case "Password:":
+			return []byte(a.password), nil
+		default:
+			return nil, fmt.Errorf("unknwon fromServer: %s", string(fromServer))
+		}
+	}
+	return nil, nil
+}
+
 type Message struct {
 	To      []string
 	From    string
@@ -135,6 +162,9 @@ func sendMail(settings *setting.Mailer, recipients []string, msgContent []byte)
 			auth = smtp.CRAMMD5Auth(settings.User, settings.Passwd)
 		} else if strings.Contains(options, "PLAIN") {
 			auth = smtp.PlainAuth("", settings.User, settings.Passwd, host)
+		} else if strings.Contains(options, "LOGIN") {
+			// Patch for AUTH LOGIN
+			auth = LoginAuth(settings.User, settings.Passwd)
 		}
 
 		if auth != nil {

File diff suppressed because it is too large
+ 0 - 0
public/css/gogs.min.css


+ 19 - 0
public/js/gogs.js

@@ -339,6 +339,25 @@ function initRepository() {
         })
     }
 
+    // Diff
+    if ($('.repository.diff').length > 0) {
+        $('.diff-detail-box .toggle.button').click(function () {
+            $($(this).data('target')).slideToggle(100);
+        })
+
+        var $counter = $('.diff-counter');
+        if ($counter.length < 1) {
+            return;
+        }
+        $counter.each(function (i, item) {
+            var $item = $(item);
+            var addLine = $item.find('span[data-line].add').data("line");
+            var delLine = $item.find('span[data-line].del').data("line");
+            var addPercent = parseFloat(addLine) / (parseFloat(addLine) + parseFloat(delLine)) * 100;
+            $item.find(".bar .add").css("width", addPercent + "%");
+        });
+    }
+
     // Pull request
     if ($('.repository.compare.pull').length > 0) {
         var $branch_dropdown = $('.choose.branch .dropdown')

+ 1 - 1
public/less/_admin.less

@@ -1,6 +1,6 @@
 .admin {
 	padding-top: 15px;
-	padding-bottom: @footer-margin * 3;
+	padding-bottom: @footer-margin * 2;
 
 	.table.segment {
 		padding: 0;

+ 20 - 0
public/less/_base.less

@@ -92,6 +92,13 @@ img {
 		&.small {
 			font-size: 0.75em;
 		}
+
+		&.truncate {
+			overflow: hidden;
+			text-overflow: ellipsis;
+			white-space: nowrap;
+			display: inline-block;
+		}
 	}
 
 	.message {
@@ -111,6 +118,19 @@ img {
 	    border-color: #F0C36D;
 		}
 	}
+	.info {
+		&.header {
+			background-color: #d9edf7!important;
+    	border-color: #85c5e5;
+		}
+		&.segment {
+    	border-color: #85c5e5;
+		}
+	}
+
+	.normal.header {
+		font-weight: normal;
+	}
 
 	.avatar.image {
 		border-radius: 3px;

+ 5 - 1
public/less/_form.less

@@ -9,7 +9,11 @@
 .ui.attached.header {
 	background: #f0f0f0;
 	.right {
-		margin-top: -6px;
+		margin-top: -5px;
+		.button {
+			padding: 8px 10px;
+			font-weight: normal;
+		}
 	}
 }
 .repository {

+ 1 - 1
public/less/_home.less

@@ -1,5 +1,5 @@
 .home {
-	padding-bottom: @footer-margin * 3;
+	padding-bottom: @footer-margin * 2;
 	.logo {
 		max-width: 250px;
 	}

+ 1 - 1
public/less/_install.less

@@ -1,6 +1,6 @@
 .install {
 	padding-top: 45px;
-	padding-bottom: @footer-margin * 3;
+	padding-bottom: @footer-margin * 2;
 	form {
 		@input-padding: 320px !important;
 		label {

+ 182 - 1
public/less/_repository.less

@@ -2,7 +2,7 @@
 	@mega-octicon-width: 30px;
 
 	padding-top: 15px;
-	padding-bottom: @footer-margin * 3;
+	padding-bottom: @footer-margin * 2;
 
 	.head {
 		.column {
@@ -424,6 +424,187 @@
 			}
 		}
 	}
+
+	&.commits {
+		.header {
+			.ui.right {
+				.search {
+					input {
+						font-weight: normal;
+						padding: 5px 10px;
+					}
+				}
+				.button {
+					float: right;
+					margin-left: 5px;
+					margin-top: 1px;
+				}
+			}
+		}
+	}
+	.commits.table {
+		font-size: 13px;
+		th, td {
+			&:first-child {
+				padding-left: 15px;
+			}
+		}
+		td {
+			line-height: 15px;
+		}
+		.author {
+			min-width: 180px;
+		}
+		.message span {
+			max-width: 500px;
+		}
+		.date {
+	    width: 120px;
+		}
+	}
+	.sha.label {
+		font-family: Consolas, Menlo, Monaco, "Lucida Console", monospace;
+		font-size: 14px;
+		padding: 6px 10px 4px 10px;
+		font-weight: normal;
+	}
+
+	.diff-detail-box {
+    margin: 15px 0;
+    line-height: 30px;
+    ol {
+      clear: both;
+      padding-left: 0;
+      margin-top: 5px;
+      margin-bottom: 28px;
+      li {
+        list-style: none;
+        padding-bottom: 4px;
+        margin-bottom: 4px;
+        border-bottom: 1px dashed #DDD;
+        padding-left: 6px;
+      }
+    }
+    span.status{
+      display: inline-block;
+      width: 12px;
+      height: 12px;
+      margin-right: 8px;
+      vertical-align: middle;
+      &.modify {
+        background-color: #f0db88;
+      }
+      &.add {
+        background-color: #b4e2b4;
+      }
+      &.del {
+        background-color: #e9aeae;
+      }
+      &.rename {
+        background-color: #dad8ff;
+      }
+    }
+	}
+	.diff-box {
+    .count {
+      margin-right: 12px;
+      .bar {
+        background-color: #e75316;
+        height: 12px;
+        width: 40px;
+        display: inline-block;
+        margin: 2px 4px 0 4px;
+        vertical-align: text-top;
+        .add {
+          background-color: #77c64a;
+          height: 12px;
+        }
+      }
+    }
+    .file {
+      color: #888;
+    }
+	}
+	.diff-file-box {
+		.header {
+			border-bottom: 1px solid #d4d4d5!important;
+		}
+    .file-body.file-code {
+      .lines-num {
+        text-align: right;
+        color: #999;
+        background: #fafafa;
+        width: 1%;
+      }
+      .lines-num-old {
+        border-right: 1px solid #DDD;
+      }
+    }
+    .code-diff {
+    	font-size: 13px;
+    	td {
+    		padding: 0;
+    		border-top: none;
+    	}
+    	pre {
+    		margin: 0;
+    	}
+    	.lines-num {
+    		border-right: 1px solid #d4d4d5;
+    		padding: 0 5px;
+    	}
+      tbody {
+        tr {
+          &.tag-code {
+            td, pre {
+              background-color: #E0E0E0 !important;
+              border-color: #ADADAD!important;
+            }
+            // td.selected-line, td.selected-line pre {
+            //   background-color: #ffffdd !important;
+            // }
+          }
+          // &.same-code {
+          //   td.selected-line, td.selected-line pre {
+          //     background-color: #ffffdd !important;
+          //   }
+          // }
+          &.del-code {
+            td, pre {
+              background-color: #ffe2dd !important;
+              border-color: #e9aeae !important;
+            }
+            // td.selected-line, td.selected-line pre {
+            //   background-color: #ffffdd !important;
+            // }
+          }
+          &.add-code {
+            td, pre { 
+              background-color: #d1ffd6 !important;
+              border-color: #b4e2b4 !important;
+            }
+            // td.selected-line, td.selected-line pre {
+            //   background-color: #ffffdd !important;
+            // }
+          }
+          &:hover {
+            td {
+              background-color: #FFF8D2 !important;
+              border-color: #F0DB88 !important;   
+            }
+            pre {
+              background-color: transparent !important;
+            }
+          }
+        }
+      }
+    }
+	}
+	.code-view {
+		overflow: auto;
+		overflow-x: auto;
+		overflow-y: hidden;
+	}
 }
 
 .ui.comments {

+ 1 - 1
public/less/_user.less

@@ -1,6 +1,6 @@
 .user {
 	padding-top: 15px;
-	padding-bottom: @footer-margin * 3;
+	padding-bottom: @footer-margin * 2;
 
 	&.settings {
 		.key.list {

+ 8 - 18
routers/repo/commit.go

@@ -9,6 +9,7 @@ import (
 	"path"
 
 	"github.com/Unknwon/com"
+	"github.com/Unknwon/paginater"
 
 	"github.com/gogits/gogs/models"
 	"github.com/gogits/gogs/modules/base"
@@ -44,7 +45,7 @@ func RenderIssueLinks(oldCommits *list.List, repoLink string) *list.List {
 }
 
 func Commits(ctx *middleware.Context) {
-	ctx.Data["IsRepoToolbarCommits"] = true
+	ctx.Data["PageIsCommits"] = true
 
 	userName := ctx.Repo.Owner.Name
 	repoName := ctx.Repo.Repository.Name
@@ -64,19 +65,11 @@ func Commits(ctx *middleware.Context) {
 		return
 	}
 
-	// Calculate and validate page number.
-	page, _ := com.StrTo(ctx.Query("p")).Int()
-	if page < 1 {
+	page := ctx.QueryInt("page")
+	if page <= 1 {
 		page = 1
 	}
-	lastPage := page - 1
-	if lastPage < 0 {
-		lastPage = 0
-	}
-	nextPage := page + 1
-	if page*50 > commitsCount {
-		nextPage = 0
-	}
+	ctx.Data["Page"] = paginater.New(commitsCount, git.CommitsRangeSize, page, 5)
 
 	// Both `git log branchName` and `git log commitId` work.
 	commits, err := ctx.Repo.Commit.CommitsByRange(page)
@@ -91,14 +84,11 @@ func Commits(ctx *middleware.Context) {
 	ctx.Data["Username"] = userName
 	ctx.Data["Reponame"] = repoName
 	ctx.Data["CommitCount"] = commitsCount
-	ctx.Data["LastPageNum"] = lastPage
-	ctx.Data["NextPageNum"] = nextPage
 	ctx.HTML(200, COMMITS)
 }
 
 func SearchCommits(ctx *middleware.Context) {
-	ctx.Data["IsSearchPage"] = true
-	ctx.Data["IsRepoToolbarCommits"] = true
+	ctx.Data["PageIsCommits"] = true
 
 	keyword := ctx.Query("q")
 	if len(keyword) == 0 {
@@ -199,7 +189,7 @@ func FileHistory(ctx *middleware.Context) {
 }
 
 func Diff(ctx *middleware.Context) {
-	ctx.Data["IsRepoToolbarCommits"] = true
+	ctx.Data["PageIsDiff"] = true
 
 	userName := ctx.Repo.Owner.Name
 	repoName := ctx.Repo.Repository.Name
@@ -253,7 +243,7 @@ func Diff(ctx *middleware.Context) {
 	ctx.Data["Parents"] = parents
 	ctx.Data["DiffNotAvailable"] = diff.NumFiles() == 0
 	ctx.Data["SourcePath"] = setting.AppSubUrl + "/" + path.Join(userName, repoName, "src", commitId)
-	if (commit.ParentCount() > 0) {
+	if commit.ParentCount() > 0 {
 		ctx.Data["BeforeSourcePath"] = setting.AppSubUrl + "/" + path.Join(userName, repoName, "src", parents[0])
 	}
 	ctx.Data["RawPath"] = setting.AppSubUrl + "/" + path.Join(userName, repoName, "raw", commitId)

+ 7 - 0
routers/repo/setting.go

@@ -677,6 +677,13 @@ func SettingsDeployKeysPost(ctx *middleware.Context, form auth.AddSSHKeyForm) {
 	ctx.Data["Title"] = ctx.Tr("repo.settings")
 	ctx.Data["PageIsSettingsKeys"] = true
 
+	keys, err := models.ListDeployKeys(ctx.Repo.Repository.ID)
+	if err != nil {
+		ctx.Handle(500, "ListDeployKeys", err)
+		return
+	}
+	ctx.Data["Deploykeys"] = keys
+
 	if ctx.HasError() {
 		ctx.HTML(200, DEPLOY_KEYS)
 		return

+ 46 - 48
routers/user/setting.go

@@ -269,12 +269,12 @@ func SettingsSSHKeys(ctx *middleware.Context) {
 	ctx.Data["Title"] = ctx.Tr("settings")
 	ctx.Data["PageIsSettingsSSHKeys"] = true
 
-	var err error
-	ctx.Data["Keys"], err = models.ListPublicKeys(ctx.User.Id)
+	keys, err := models.ListPublicKeys(ctx.User.Id)
 	if err != nil {
-		ctx.Handle(500, "ssh.ListPublicKey", err)
+		ctx.Handle(500, "ListPublicKeys", err)
 		return
 	}
+	ctx.Data["Keys"] = keys
 
 	ctx.HTML(200, SETTINGS_SSH_KEYS)
 }
@@ -283,66 +283,58 @@ func SettingsSSHKeysPost(ctx *middleware.Context, form auth.AddSSHKeyForm) {
 	ctx.Data["Title"] = ctx.Tr("settings")
 	ctx.Data["PageIsSettingsSSHKeys"] = true
 
-	var err error
-	ctx.Data["Keys"], err = models.ListPublicKeys(ctx.User.Id)
+	keys, err := models.ListPublicKeys(ctx.User.Id)
 	if err != nil {
-		ctx.Handle(500, "ssh.ListPublicKey", err)
+		ctx.Handle(500, "ListPublicKeys", err)
 		return
 	}
+	ctx.Data["Keys"] = keys
 
-	// Delete SSH key.
-	if ctx.Query("_method") == "DELETE" {
-		id := com.StrTo(ctx.Query("id")).MustInt64()
-		if id <= 0 {
-			return
-		}
+	if ctx.HasError() {
+		ctx.HTML(200, SETTINGS_SSH_KEYS)
+		return
+	}
 
-		if err = models.DeletePublicKey(&models.PublicKey{ID: id}); err != nil {
-			ctx.Handle(500, "DeletePublicKey", err)
+	content, err := models.CheckPublicKeyString(form.Content)
+	if err != nil {
+		if err == models.ErrKeyUnableVerify {
+			ctx.Flash.Info(ctx.Tr("form.unable_verify_ssh_key"))
 		} else {
-			log.Trace("SSH key deleted: %s", ctx.User.Name)
+			ctx.Flash.Error(ctx.Tr("form.invalid_ssh_key", err.Error()))
 			ctx.Redirect(setting.AppSubUrl + "/user/settings/ssh")
+			return
 		}
-		return
 	}
 
-	// Add new SSH key.
-	if ctx.Req.Method == "POST" {
-		if ctx.HasError() {
-			ctx.HTML(200, SETTINGS_SSH_KEYS)
-			return
+	if err = models.AddPublicKey(ctx.User.Id, form.Title, content); err != nil {
+		ctx.Data["HasError"] = true
+		switch {
+		case models.IsErrKeyAlreadyExist(err):
+			ctx.Data["Err_Content"] = true
+			ctx.RenderWithErr(ctx.Tr("settings.ssh_key_been_used"), SETTINGS_SSH_KEYS, &form)
+		case models.IsErrKeyNameAlreadyUsed(err):
+			ctx.Data["Err_Title"] = true
+			ctx.RenderWithErr(ctx.Tr("settings.ssh_key_name_used"), SETTINGS_SSH_KEYS, &form)
+		default:
+			ctx.Handle(500, "AddPublicKey", err)
 		}
+		return
+	}
 
-		content, err := models.CheckPublicKeyString(form.Content)
-		if err != nil {
-			if err == models.ErrKeyUnableVerify {
-				ctx.Flash.Info(ctx.Tr("form.unable_verify_ssh_key"))
-			} else {
-				ctx.Flash.Error(ctx.Tr("form.invalid_ssh_key", err.Error()))
-				ctx.Redirect(setting.AppSubUrl + "/user/settings/ssh")
-				return
-			}
-		}
+	ctx.Flash.Success(ctx.Tr("settings.add_key_success", form.Title))
+	ctx.Redirect(setting.AppSubUrl + "/user/settings/ssh")
+}
 
-		if err = models.AddPublicKey(ctx.User.Id, form.Title, content); err != nil {
-			switch {
-			case models.IsErrKeyAlreadyExist(err):
-				ctx.RenderWithErr(ctx.Tr("settings.ssh_key_been_used"), SETTINGS_SSH_KEYS, &form)
-			case models.IsErrKeyNameAlreadyUsed(err):
-				ctx.RenderWithErr(ctx.Tr("settings.ssh_key_name_used"), SETTINGS_SSH_KEYS, &form)
-			default:
-				ctx.Handle(500, "AddPublicKey", err)
-			}
-			return
-		} else {
-			log.Trace("SSH key added: %s", ctx.User.Name)
-			ctx.Flash.Success(ctx.Tr("settings.add_key_success", form.Title))
-			ctx.Redirect(setting.AppSubUrl + "/user/settings/ssh")
-			return
-		}
+func DeleteSSHKey(ctx *middleware.Context) {
+	if err := models.DeletePublicKey(ctx.QueryInt64("id")); err != nil {
+		ctx.Flash.Error("DeletePublicKey: " + err.Error())
+	} else {
+		ctx.Flash.Success(ctx.Tr("settings.ssh_key_deletion_success"))
 	}
 
-	ctx.HTML(200, SETTINGS_SSH_KEYS)
+	ctx.JSON(200, map[string]interface{}{
+		"redirect": setting.AppSubUrl + "/user/settings/ssh",
+	})
 }
 
 func SettingsSocial(ctx *middleware.Context) {
@@ -389,6 +381,12 @@ func SettingsApplicationsPost(ctx *middleware.Context, form auth.NewAccessTokenF
 	ctx.Data["PageIsSettingsApplications"] = true
 
 	if ctx.HasError() {
+		tokens, err := models.ListAccessTokens(ctx.User.Id)
+		if err != nil {
+			ctx.Handle(500, "ListAccessTokens", err)
+			return
+		}
+		ctx.Data["Tokens"] = tokens
 		ctx.HTML(200, SETTINGS_APPLICATIONS)
 		return
 	}

+ 7 - 8
templates/repo/commits.tmpl

@@ -1,9 +1,8 @@
-{{template "ng/base/head" .}}
-{{template "ng/base/header" .}}
-<div id="repo-wrapper">
-    {{template "repo/header_old" .}}
-	<div class="container clear">
-  		{{template "repo/commits_table" .}}
-  	</div>
+{{template "base/head" .}}
+<div class="repository commits">
+	{{template "repo/header" .}}
+  <div class="ui container">
+		{{template "repo/commits_table" .}}
+	</div>
 </div>
-{{template "ng/base/footer" .}}
+{{template "base/footer" .}}

+ 66 - 46
templates/repo/commits_table.tmpl

@@ -1,48 +1,68 @@
-<div id="commits-list">
-    <div class="panel panel-radius">
-        <div class="panel-header">
-            {{if not .IsDiffCompare}}
-            <form class="search pull-right" action="{{.RepoLink}}/commits/{{.BranchName}}/search" method="get" id="commits-search-form">
-                <input class="ipt ipt-radius" type="search" name="q" placeholder="{{.i18n.Tr "repo.commits.search"}}" value="{{.Keyword}}" />
-                <button class="btn btn-black btn-small btn-radius">{{.i18n.Tr "repo.commits.find"}}</button>
-            </form>
-            {{end}}
-            <h4>{{.CommitCount}} {{.i18n.Tr "repo.commits.commits"}}</h4>
-        </div>
-        <table class="panel-body table commit-list table-striped">
-            <thead>
-                <tr>
-                    <th class="author">{{.i18n.Tr "repo.commits.author"}}</th>
-                    <th class="sha">SHA1</th>
-                    <th class="message">{{.i18n.Tr "repo.commits.message"}}</th>
-                    <th class="date">{{.i18n.Tr "repo.commits.date"}}</th>
-                </tr>
-            </thead>
-            <tbody>
-            {{ $username := .Username}}
-            {{ $reponame := .Reponame}}
-            {{$r := List .Commits}}
-            {{range $r}}
-            <tr>
-                <td class="author">
-                    {{if .User}}
-                    <img class="avatar-20" src="{{.User.AvatarLink}}" alt=""/>&nbsp;&nbsp;&nbsp;<a href="{{AppSubUrl}}/{{.User.Name}}">{{.Author.Name}}</a>
-                    {{else}}
-                    <img class="avatar-20" src="{{AvatarLink .Author.Email}}" alt=""/>&nbsp;&nbsp;&nbsp;{{.Author.Name}}
-                    {{end}}
-                </td>
-                <td class="sha"><a rel="nofollow" class="label label-green" href="{{AppSubUrl}}/{{$username}}/{{$reponame}}/commit/{{.Id}} ">{{SubStr .Id.String 0 10}} </a></td>
-                <td class="message"><span class="text-truncate">{{RenderCommitMessage .Summary $.RepoLink}}</span></td>
-                <td class="date">{{TimeSince .Author.When $.Lang}}</td>
-            </tr>
-            {{end}}
-            </tbody>
-        </table>
-    </div>
-    {{if and (not .IsSearchPage) (not .IsDiffCompare)}}
-    <ul class="pagination">
-        {{if .LastPageNum}}<li><a class="btn btn-medium btn-gray btn-radius" href="{{.RepoLink}}/commits/{{.BranchName}}{{if .FileName}}/{{.FileName}}{{end}}?p={{.LastPageNum}}" rel="nofollow">&laquo; {{.i18n.Tr "repo.commits.newer"}}</a></li>{{end}}
-        {{if .NextPageNum}}<li><a class="btn btn-medium btn-gray btn-radius" href="{{.RepoLink}}/commits/{{.BranchName}}{{if .FileName}}/{{.FileName}}{{end}}?p={{.NextPageNum}}" rel="nofollow">&raquo; {{.i18n.Tr "repo.commits.older"}}</a></li>{{end}}
-    </ul>
+<h4 class="ui top attached header">
+  {{.CommitCount}} {{.i18n.Tr "repo.commits.commits"}}
+  {{if .PageIsCommits}}
+  <div class="ui right">
+    <form action="{{.RepoLink}}/commits/{{.BranchName}}/search">
+      <div class="ui tiny search input">
+        <input name="q" placeholder="{{.i18n.Tr "repo.commits.search"}}" value="{{.Keyword}}" autofocus>
+      </div>
+      <button class="ui black tiny button" data-panel="#add-deploy-key-panel">{{.i18n.Tr "repo.commits.find"}}</button>
+    </form>
+  </div>
+  {{else if .IsDiffCompare}}
+  <a href="{{$.RepoLink}}/commit/{{.BeforeCommitId}}" class="ui green sha label">{{ShortSha .BeforeCommitId}}</a> ... <a href="{{$.RepoLink}}/commit/{{.AfterCommitId}}" class="ui green sha label">{{ShortSha .AfterCommitId}}</a>
+  {{end}}
+</h4>
+<div class="ui attached table segment">
+  <table class="ui very basic striped commits table">
+    <thead>
+      <tr>
+        <th>{{.i18n.Tr "repo.commits.author"}}</th>
+        <th>SHA1</th>
+        <th>{{.i18n.Tr "repo.commits.message"}}</th>
+        <th>{{.i18n.Tr "repo.commits.date"}}</th>
+      </tr>
+    </thead>
+    <tbody>
+    {{ $username := .Username}}
+    {{ $reponame := .Reponame}}
+    {{  $r:= List .Commits}}
+    {{range $r}}
+      <tr>
+        <td class="author">
+          {{if .User}}
+          <img class="ui avatar image" src="{{.User.AvatarLink}}" alt=""/>&nbsp;&nbsp;<a href="{{AppSubUrl}}/{{.User.Name}}">{{.Author.Name}}</a>
+          {{else}}
+          <img class="ui avatar image" src="{{AvatarLink .Author.Email}}" alt=""/>&nbsp;&nbsp;{{.Author.Name}}
+          {{end}}
+        </td>
+        <td class="sha"><a rel="nofollow" class="ui green sha label" href="{{AppSubUrl}}/{{$username}}/{{$reponame}}/commit/{{.Id}} ">{{SubStr .Id.String 0 10}} </a></td>
+        <td class="message"><span class="text truncate">{{RenderCommitMessage .Summary $.RepoLink}}</span></td>
+        <td class="date">{{TimeSince .Author.When $.Lang}}</td>
+      </tr>
     {{end}}
+    </tbody>
+  </table>
 </div>
+
+{{with .Page}}
+{{if gt .TotalPages 1}}
+<div class="center page buttons">
+  <div class="ui borderless pagination menu">
+    <a class="{{if not .HasPrevious}}disabled{{end}} item" {{if .HasPrevious}}href="{{$.RepoLink}}/commits/{{$.BranchName}}{{if $.FileName}}/{{$.FileName}}{{end}}?page={{.Previous}}"{{end}}>
+      <i class="left arrow icon"></i> {{$.i18n.Tr "repo.issues.previous"}}
+    </a>
+    {{range .Pages}}
+    {{if eq .Num -1}}
+    <a class="disabled item">...</a>
+    {{else}}
+    <a class="{{if .IsCurrent}}active{{end}} item" {{if not .IsCurrent}}href="{{$.RepoLink}}/commits/{{$.BranchName}}{{if $.FileName}}/{{$.FileName}}{{end}}?page={{.Num}}"{{end}}>{{.Num}}</a>
+    {{end}}
+    {{end}}
+    <a class="{{if not .HasNext}}disabled{{end}} item" {{if .HasNext}}href="{{$.RepoLink}}/commits/{{$.BranchName}}{{if $.FileName}}/{{$.FileName}}{{end}}?page={{.Next}}"{{end}}>
+      {{$.i18n.Tr "repo.issues.next"}} <i class="icon right arrow"></i>
+    </a>
+  </div>
+</div>
+{{end}}
+{{end}}

+ 128 - 126
templates/repo/diff.tmpl

@@ -1,134 +1,136 @@
-{{template "ng/base/head" .}}
-{{template "ng/base/header" .}}
-<div id="repo-wrapper">
-    {{template "repo/header_old" .}}
-    <div class="container clear" id="diff-page">
-        {{if .IsDiffCompare }}
-        <div class="panel panel-info panel-radius compare-head-box">
-            <div class="panel-header">
-                <a class="pull-right btn btn-blue btn-header btn-medium btn-radius" rel="nofollow" href="{{EscapePound .SourcePath}}">{{.i18n.Tr "repo.diff.browse_source"}}</a>
-                <h4><a href="{{$.RepoLink}}/commit/{{.BeforeCommitId}}" class="label label-green">{{ShortSha .BeforeCommitId}}</a> ... <a href="{{$.RepoLink}}/commit/{{.AfterCommitId}}" class="label label-green">{{ShortSha .AfterCommitId}}</a></h4>
-            </div>
-            <div class="panel-body compare">
-                {{template "repo/commits_table" .}}
-            </div>
+{{template "base/head" .}}
+<div class="repository diff">
+  {{template "repo/header" .}}
+  <div class="ui container">
+    {{if .IsDiffCompare }}
+    {{template "repo/commits_table" .}}
+    {{else}}
+    <h4 class="ui top attached info header">
+      {{RenderCommitMessage .Commit.Message $.RepoLink}}
+      <div class="ui right">
+        <a class="ui blue tiny button" href="{{EscapePound .SourcePath}}">
+          {{.i18n.Tr "repo.diff.browse_source"}}
+        </a>
+      </div>
+    </h4>
+    <div class="ui attached info segment">
+      {{if .Author}}
+      <img class="ui avatar image" src="{{.Author.AvatarLink}}" />
+      <a href="{{.Author.HomeLink}}"><strong>{{.Commit.Author.Name}}</strong></a>
+      {{else}}
+      <img class="ui avatar image" src="{{AvatarLink .Commit.Author.Email}}" />
+      <strong>{{.Commit.Author.Name}}</strong>
+      {{end}}
+      <span class="text grey" id="authored-time">{{TimeSince .Commit.Author.When $.Lang}}</span>
+      <div class="ui right">
+        <div class="ui horizontal list">
+          <div class="item">
+            {{.i18n.Tr "repo.diff.parent"}}
+          </div>
+          <div class="item">
+            {{range .Parents}}
+            <a class="ui blue sha label" href="{{$.RepoLink}}/commit/{{.}}">{{ShortSha .}}</a>
+            {{end}}
+          </div>
+          <div class="item">{{.i18n.Tr "repo.diff.commit"}}</div>
+          <div class="item"><span class="ui blue sha label">{{ShortSha .CommitId}}</span></div>
         </div>
-        {{else}}
-        <div class="panel panel-info panel-radius diff-head-box">
-            <div class="panel-header">
-                <a class="pull-right btn btn-blue btn-header btn-medium btn-radius" rel="nofollow" href="{{EscapePound .SourcePath}}">{{.i18n.Tr "repo.diff.browse_source"}}</a>
-                <h4 class="commit-message">{{RenderCommitMessage .Commit.Message $.RepoLink}}</h4>
-            </div>
-            <div class="panel-body">
-                <span class="pull-right">
-                    <ul class="list-unstyled">
-                        <li class="inline">{{.i18n.Tr "repo.diff.parent"}}</li>
-                        {{range .Parents}}
-                        <li class="inline"><a href="{{$.RepoLink}}/commit/{{.}}"><span class="label label-blue">{{ShortSha .}}</span></a></li>
-                        {{end}}
-                        <li class="inline">{{.i18n.Tr "repo.diff.commit"}} <span class="label label-blue">{{ShortSha .CommitId}}</span></li>
-                    </ul>
-                </span>
-                <p class="author">
-                    {{if .Author}}
-                    <img class="avatar-30" src="{{.Author.AvatarLink}}" />
-                    <a href="{{AppSubUrl}}/{{.Author.Name}}"><strong>{{.Commit.Author.Name}}</strong></a>
-                    {{else}}
-                    <img class="avatar-30" src="{{AvatarLink .Commit.Author.Email}}" />
-                    <strong>{{.Commit.Author.Name}}</strong>
-                    {{end}}
-                    <span class="text-grey" id="authored-time">{{TimeSince .Commit.Author.When $.Lang}}</span>
-                </p>
-            </div>
+      </div>
+    </div>
+    {{end}}
+    
+    {{if .DiffNotAvailable}}
+    <h4>{{.i18n.Tr "repo.diff.data_not_available"}}</h4>
+    {{else}}
+    <div class="diff-detail-box diff-box">
+      <div>
+        <i class="fa fa-retweet"></i>
+        {{.i18n.Tr "repo.diff.stats_desc" .Diff.NumFiles .Diff.TotalAddition .Diff.TotalDeletion | Str2html}}
+        <div class="ui right">
+          <a class="ui tiny basic black toggle button" data-target="#diff-files">{{.i18n.Tr "repo.diff.show_diff_stats"}}</a>
         </div>
+      </div>
+      <ol class="detail-files hide" id="diff-files">
+        {{range .Diff.Files}}
+        <li>
+          <div class="diff-counter count pull-right">
+            {{if not .IsBin}}
+            <span class="add" data-line="{{.Addition}}">{{.Addition}}</span>
+            <span class="bar">
+              <span class="pull-left add"></span>
+              <span class="pull-left del"></span>
+            </span>
+            <span class="del" data-line="{{.Deletion}}">{{.Deletion}}</span>
+            {{else}}
+            <span>{{$.i18n.Tr "repo.diff.bin"}}</span>
+            {{end}}
+          </div>
+          <!-- todo finish all file status, now modify, add, delete and rename -->
+          <span class="status {{DiffTypeToStr .Type}} poping up" data-content="{{DiffTypeToStr .Type}}" data-variation="inverted tiny" data-position="right center">&nbsp;</span>
+          <a class="file" href="#diff-{{.Index}}">{{.Name}}</a>
+        </li>
         {{end}}
-        {{if .DiffNotAvailable}}
-        <h4>{{.i18n.Tr "repo.diff.data_not_available"}}</h4>
-        {{else}}
-        <div class="diff-detail-box diff-box">
-            <a class="pull-right btn btn-gray btn-header btn-radius text-black" data-target="#diff-files">{{.i18n.Tr "repo.diff.show_diff_stats"}}</a>
-            <p class="showing">
-                <i class="fa fa-retweet"></i>
-                {{.i18n.Tr "repo.diff.stats_desc" .Diff.NumFiles .Diff.TotalAddition .Diff.TotalDeletion | Str2html}}
-            </p>
-            <ol class="detail-files collapse hide" id="diff-files">
-                {{range .Diff.Files}}
-                <li>
-                    <div class="diff-counter count pull-right">
-                        {{if not .IsBin}}
-                        <span class="add" data-line="{{.Addition}}">{{.Addition}}</span>
-                        <span class="bar">
-                            <span class="pull-left add"></span>
-                            <span class="pull-left del"></span>
-                        </span>
-                        <span class="del" data-line="{{.Deletion}}">{{.Deletion}}</span>
-                        {{else}}
-                        <span>{{$.i18n.Tr "repo.diff.bin"}}</span>
-                        {{end}}
-                    </div>
-                    <!-- todo finish all file status, now modify, add, delete and rename -->
-                    <span class="status {{DiffTypeToStr .Type}}" data-toggle="tooltip" data-placement="right" title="{{DiffTypeToStr .Type}}">&nbsp;</span>
-                    <a class="file" href="#diff-{{.Index}}">{{.Name}}</a>
-                </li>
-                {{end}}
-            </ol>
-        </div>
-
-        {{range $i, $file := .Diff.Files}}
-        <div class="panel panel-radius diff-file-box diff-box file-content" id="diff-{{.Index}}">
-            <div class="panel-header">
-                <div class="diff-counter count pull-left">
-                    {{if not $file.IsBin}}
-                    <span class="add" data-line="{{.Addition}}">+ {{.Addition}}</span>
-                    <span class="bar">
-                        <span class="pull-left add"></span>
-                        <span class="pull-left del"></span>
-                    </span>
-                    <span class="del" data-line="{{.Deletion}}">- {{.Deletion}}</span>
-                    {{else}}
-                    {{$.i18n.Tr "repo.diff.bin"}}
-                    {{end}}
-                </div>
-                {{if $file.IsDeleted}}
-                <a class="btn btn-gray btn-header btn-radius text-black pull-right" rel="nofollow" href="{{EscapePound $.BeforeSourcePath}}/{{EscapePound .Name}}">{{$.i18n.Tr "repo.diff.view_file"}}</a>
-                {{else}}
-                <a class="btn btn-gray btn-header btn-radius text-black pull-right" rel="nofollow" href="{{EscapePound $.SourcePath}}/{{EscapePound .Name}}">{{$.i18n.Tr "repo.diff.view_file"}}</a>
-                {{end}}
-                <span class="file">{{$file.Name}}</span>
-            </div>
-            {{$isImage := (call $.IsImageFile $file.Name)}}
-            <div class="panel-body file-body file-code code-view code-diff">
-                {{if $isImage}}
-                    <div class="text-center">
-                        <img src="{{$.RawPath}}/{{EscapePound .Name}}">
-                    </div>
-                {{else}}
-                <table>
-                    <tbody>
-                        {{range .Sections}}
-                        {{range $k, $line := .Lines}}
-                        <tr class="{{DiffLineTypeToStr .Type}}-code nl-{{$k}} ol-{{$k}}">
-                            <td class="lines-num lines-num-old">
-                                <span rel="{{if $line.LeftIdx}}diff-{{Sha1 $file.Name}}L{{$line.LeftIdx}}{{end}}">{{if $line.LeftIdx}}{{$line.LeftIdx}}{{end}}</span>
-                            </td>
-                            <td class="lines-num lines-num-new">
-                                <span rel="{{if $line.RightIdx}}diff-{{Sha1 $file.Name}}R{{$line.RightIdx}}{{end}}">{{if $line.RightIdx}}{{$line.RightIdx}}{{end}}</span>
-                            </td>
+      </ol>
+    </div>
 
-                            <td class="lines-code">
-                                <pre>{{$line.Content}}</pre>
-                            </td>
-                        </tr>
-                        {{end}}
-                        {{end}}
-                    </tbody>
-                </table>
-                {{end}}
-            </div>
+    {{range $i, $file := .Diff.Files}}
+    <div class="diff-file-box diff-box file-content" id="diff-{{.Index}}">
+      <h4 class="ui top attached normal header">
+        <div class="diff-counter count ui left">
+            {{if not $file.IsBin}}
+            <span class="add" data-line="{{.Addition}}">+ {{.Addition}}</span>
+            <span class="bar">
+              <span class="pull-left add"></span>
+              <span class="pull-left del"></span>
+            </span>
+            <span class="del" data-line="{{.Deletion}}">- {{.Deletion}}</span>
+            {{else}}
+            {{$.i18n.Tr "repo.diff.bin"}}
+            {{end}}
+        </div>
+        <span class="file">{{$file.Name}}</span>
+        <div class="ui right">
+          {{if $file.IsDeleted}}
+          <a class="ui basic tiny button" rel="nofollow" href="{{EscapePound $.BeforeSourcePath}}/{{EscapePound .Name}}">{{$.i18n.Tr "repo.diff.view_file"}}</a>
+          {{else}}
+          <a class="ui basic tiny button" rel="nofollow" href="{{EscapePound $.SourcePath}}/{{EscapePound .Name}}">{{$.i18n.Tr "repo.diff.view_file"}}</a>
+          {{end}}
+        </div>
+      </h4>
+      <div class="ui attached table segment">
+        {{$isImage := (call $.IsImageFile $file.Name)}}
+        {{if $isImage}}
+        <div class="center">
+          <img src="{{$.RawPath}}/{{EscapePound .Name}}">
+        </div>
+        {{else}}
+        <div class="file-body file-code code-view code-diff">
+          <table>
+            <tbody>
+              {{range .Sections}}
+              {{range $k, $line := .Lines}}
+              <tr class="{{DiffLineTypeToStr .Type}}-code nl-{{$k}} ol-{{$k}}">
+                <td class="lines-num lines-num-old">
+                  <span rel="{{if $line.LeftIdx}}diff-{{Sha1 $file.Name}}L{{$line.LeftIdx}}{{end}}">{{if $line.LeftIdx}}{{$line.LeftIdx}}{{end}}</span>
+                </td>
+                <td class="lines-num lines-num-new">
+                  <span rel="{{if $line.RightIdx}}diff-{{Sha1 $file.Name}}R{{$line.RightIdx}}{{end}}">{{if $line.RightIdx}}{{$line.RightIdx}}{{end}}</span>
+                </td>
+                <td class="lines-code">
+                  <pre>{{$line.Content}}</pre>
+                </td>
+              </tr>
+              {{end}}
+              {{end}}
+            </tbody>
+          </table>
         </div>
-        <br>
-        {{end}}
         {{end}}
+      </div>
     </div>
+    <br>
+    {{end}}
+    {{end}}
+  </div>
 </div>
-{{template "ng/base/footer" .}}
+{{template "base/footer" .}}

+ 1 - 1
templates/repo/issue/view_content.tmpl

@@ -102,7 +102,7 @@
 					  	</div>
 					  	{{end}}
 					  	{{if or $.IsRepositoryAdmin (eq .Poster.Id $.SignedUserID)}}
-							<a class="edit-content item" href="#" data-type="comment"><i class="octicon octicon-pencil"></i></a>
+							<a class="edit-content item" href="#"><i class="octicon octicon-pencil"></i></a>
 					  	{{end}}
 					  </div>
 					</div>

+ 4 - 4
templates/repo/settings/deploy_keys.tmpl

@@ -53,12 +53,12 @@
 						<form class="ui form" action="{{.Link}}" method="post">
 							{{.CsrfTokenHtml}}
 							<div class="field {{if .Err_Title}}error{{end}}">
-								<label>{{.i18n.Tr "repo.settings.title"}}</label>
-								<input name="title" value="{{.title}}" autofocus required>
+								<label for="title">{{.i18n.Tr "repo.settings.title"}}</label>
+								<input id="title" name="title" value="{{.title}}" autofocus required>
 							</div>
 							<div class="field {{if .Err_Content}}error{{end}}">
-								<label>{{.i18n.Tr "repo.settings.deploy_key_content"}}</label>
-								<textarea name="content" required>{{.content}}</textarea>
+								<label for="content">{{.i18n.Tr "repo.settings.deploy_key_content"}}</label>
+								<textarea id="content" name="content" required>{{.content}}</textarea>
 							</div>
 							<button class="ui green button">
 								{{.i18n.Tr "repo.settings.add_deploy_key"}}

+ 2 - 0
templates/user/settings/nav.tmpl

@@ -6,7 +6,9 @@
             <li {{if .PageIsSettingsPassword}}class="current"{{end}}><a href="{{AppSubUrl}}/user/settings/password">{{.i18n.Tr "settings.password"}}</a></li>
             <li {{if .PageIsSettingsEmails}}class="current"{{end}}><a href="{{AppSubUrl}}/user/settings/email">{{.i18n.Tr "settings.emails"}}</a></li>
             <li {{if .PageIsSettingsSSHKeys}}class="current"{{end}}><a href="{{AppSubUrl}}/user/settings/ssh">{{.i18n.Tr "settings.ssh_keys"}}</a></li>
+            {{if .HasOAuthService}}
             <li {{if .PageIsSettingsSocial}}class="current"{{end}}><a href="{{AppSubUrl}}/user/settings/social">{{.i18n.Tr "settings.social"}}</a></li>
+            {{end}}
             <li {{if .PageIsSettingsApplications}}class="current"{{end}}><a href="{{AppSubUrl}}/user/settings/applications">{{.i18n.Tr "settings.applications"}}</a></li>
             <li {{if .PageIsSettingsDelete}}class="current"{{end}}><a href="{{AppSubUrl}}/user/settings/delete">{{.i18n.Tr "settings.delete"}}</a></li>
         </ul>

+ 87 - 58
templates/user/settings/sshkeys.tmpl

@@ -1,63 +1,92 @@
-{{template "ng/base/head" .}}
-{{template "ng/base/header" .}}
-<div id="setting-wrapper" class="main-wrapper">
-    <div id="user-profile-setting" class="container clear">
-        {{template "user/settings/nav" .}}
-        <div class="grid-4-5 left">
-            <div class="setting-content">
-                {{template "ng/base/alert" .}}
-                <div id="user-ssh-setting-content">
-                    <div id="user-ssh-panel" class="panel panel-radius">
-                        <div class="panel-header">
-                            <a class="show-form-btn" data-target-form="#user-ssh-add-form">
-                                <button class="btn btn-medium btn-black btn-radius right">{{.i18n.Tr "settings.add_key"}}</button>
-                            </a>
-                            <strong>{{.i18n.Tr "settings.manage_ssh_keys"}}</strong>
-                        </div>
-                        <ul class="panel-body setting-list">
-                            <li>{{.i18n.Tr "settings.ssh_desc"}}</li>
-                            {{range .Keys}}
-                            <li class="ssh clear">
-                                <span class="active-icon left label label-{{if .HasRecentActivity}}green{{else}}gray{{end}} label-radius"></span>
-                                <i class="mega-octicon octicon-key left"></i>
-                                <div class="ssh-content left">
-                                    <p><strong>{{.Name}}</strong></p>
-                                    <p class="print">{{.Fingerprint}}</p>
-                                    <p class="activity"><i>{{$.i18n.Tr "settings.add_on"}} <span title="{{DateFmtLong .Created}}">{{DateFmtShort .Created}}</span> —  <i class="octicon octicon-info"></i>{{if .HasUsed}}{{$.i18n.Tr "settings.last_used"}} <span title="{{DateFmtLong .Updated}}">{{DateFmtShort .Updated}}</span>{{else}}{{$.i18n.Tr "settings.no_activity"}}{{end}}</i></p>
-                                </div>
-                                <form action="{{AppSubUrl}}/user/settings/ssh" method="post">
-                                    {{$.CsrfTokenHtml}}
-                                    <input name="_method" type="hidden" value="DELETE">
-                                    <input name="id" type="hidden" value="{{.ID}}">
-                                    <button class="right ssh-btn btn btn-red btn-radius btn-small">{{$.i18n.Tr "settings.delete_key"}}</button>
-                                </form>
-                            </li>
-                            {{end}}
-                        </ul>
-                    </div>
-                    <p>{{.i18n.Tr "settings.ssh_helper" "https://help.github.com/articles/generating-ssh-keys" "https://help.github.com/ssh-issues/" | Str2html}}</p>
-                    <br>
-                    <form class="panel panel-radius form form-align form-settings-add hide" id="user-ssh-add-form" action="{{AppSubUrl}}/user/settings/ssh" method="post">
-                        {{.CsrfTokenHtml}}
-                        <p class="panel-header"><strong>{{.i18n.Tr "settings.add_new_key"}}</strong></p>
-                        <div class="panel-body">
-                            <p class="field">
-                                <label class="req" for="ssh-title">{{.i18n.Tr "settings.key_name"}}</label>
-                                <input class="ipt ipt-radius" id="ssh-title" name="title" type="text" required />
-                            </p>
-                            <p class="field clear">
-                                <label class="left req" for="ssh-key">{{.i18n.Tr "settings.key_content"}}</label>
-                                <textarea class="ipt ipt-radius left" name="content" id="ssh-key" required></textarea>
-                            </p>
-                            <p class="field">
-                                <label></label>
-                                <button class="btn btn-green btn-radius" id="ssh-add-btn">{{.i18n.Tr "settings.add_key"}}</button>
-                            </p>
-                        </div>
-                    </form>
+{{template "base/head" .}}
+<div class="user settings">
+  <div class="ui container">
+    <div class="ui grid">
+      {{template "user/settings/navbar" .}}
+      <div class="twelve wide column content">
+        {{template "base/alert" .}}
+        <h4 class="ui top attached header">
+          {{.i18n.Tr "settings.manage_ssh_keys"}}
+          <div class="ui right">
+            <div class="ui blue tiny show-panel button" data-panel="#add-ssh-key-panel">{{.i18n.Tr "settings.add_key"}}</div>
+          </div>
+        </h4>
+        <div class="ui attached segment">
+          <div class="ui key list">
+            <div class="item">
+              {{.i18n.Tr "settings.ssh_desc"}}
+            </div>
+            {{range .Keys}}
+            <div class="item ui grid">
+              <div class="one wide column">
+                <i class="ssh-key-state-indicator fa fa-circle{{if .HasRecentActivity}} active invert poping up{{else}}-o{{end}}" {{if .HasRecentActivity}}data-content="{{$.i18n.Tr "settings.key_state_desc"}}" data-variation="inverted"{{end}}></i>
+              </div>
+              <div class="one wide column">
+                <i class="mega-octicon octicon-key left"></i>
+              </div>
+              <div class="eleven wide column">
+                <strong>{{.Name}}</strong>
+                <div class="print meta">
+                  {{.Fingerprint}}
+                </div>
+                <div class="activity meta">
+                  <i>{{$.i18n.Tr "settings.add_on"}} <span>{{DateFmtShort .Created}}</span> —  <i class="octicon octicon-info"></i> {{if .HasUsed}}{{$.i18n.Tr "settings.last_used"}} <span>{{DateFmtShort .Updated}}</span>{{else}}{{$.i18n.Tr "settings.no_activity"}}{{end}}</i>
                 </div>
+              </div>
+              <div class="two wide column">
+                <button class="ui red tiny button delete-button" data-url="{{$.Link}}/delete" data-id="{{.ID}}">
+                  {{$.i18n.Tr "settings.delete_key"}}
+                </button>
+              </div>
             </div>
+            {{end}}
+          </div>
+        </div>
+        <br>
+        <p>{{.i18n.Tr "settings.ssh_helper" "https://help.github.com/articles/generating-ssh-keys" "https://help.github.com/ssh-issues/" | Str2html}}</p>
+        <div {{if not .HasError}}class="hide"{{end}} id="add-ssh-key-panel">
+          <h4 class="ui top attached header">
+            {{.i18n.Tr "settings.add_new_key"}}
+          </h4>
+          <div class="ui attached segment">
+            <form class="ui form" action="{{.Link}}" method="post">
+              {{.CsrfTokenHtml}}
+              <div class="field {{if .Err_Title}}error{{end}}">
+                <label for="title">{{.i18n.Tr "settings.key_name"}}</label>
+                <input id="title" name="title" value="{{.title}}" autofocus required>
+              </div>
+              <div class="field {{if .Err_Content}}error{{end}}">
+                <label for="content">{{.i18n.Tr "settings.key_content"}}</label>
+                <textarea id="content" name="content" required>{{.content}}</textarea>
+              </div>
+              <button class="ui green button">
+                {{.i18n.Tr "settings.add_key"}}
+              </button>
+            </form>
+          </div>
         </div>
+      </div>
+    </div>
+  </div>
+</div>
+
+<div class="ui small basic delete modal">
+  <div class="ui icon header">
+    <i class="trash icon"></i>
+    {{.i18n.Tr "settings.ssh_key_deletion"}}
+  </div>
+  <div class="content">
+    <p>{{.i18n.Tr "settings.ssh_key_deletion_desc"}}</p>
+  </div>
+  <div class="actions">
+    <div class="ui red basic inverted cancel button">
+      <i class="remove icon"></i>
+      {{.i18n.Tr "modal.no"}}
+    </div>
+    <div class="ui green basic inverted ok button">
+      <i class="checkmark icon"></i>
+      {{.i18n.Tr "modal.yes"}}
     </div>
+  </div>
 </div>
-{{template "ng/base/footer" .}}
+{{template "base/footer" .}}

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