mirror of
				https://gitee.com/gitea/gitea
				synced 2025-11-04 16:40:24 +08:00 
			
		
		
		
	Render READMEs in docs/ .gitea or .github from root (#10361)
* Render READMEs in docs/ .gitea or .github from root
This commit is contained in:
		@@ -80,4 +80,3 @@ INTERNAL_TOKEN = eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYmYiOjE0OTI3OTU5ODN9.O
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
[oauth2]
 | 
					[oauth2]
 | 
				
			||||||
JWT_SECRET = KZb_QLUd4fYVyxetjxC4eZkrBgWM2SndOOWDNtgUUko
 | 
					JWT_SECRET = KZb_QLUd4fYVyxetjxC4eZkrBgWM2SndOOWDNtgUUko
 | 
				
			||||||
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -50,6 +50,12 @@ func (err ErrBadLink) Error() string {
 | 
				
			|||||||
	return fmt.Sprintf("%s: %s", err.Name, err.Message)
 | 
						return fmt.Sprintf("%s: %s", err.Name, err.Message)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// IsErrBadLink if some error is ErrBadLink
 | 
				
			||||||
 | 
					func IsErrBadLink(err error) bool {
 | 
				
			||||||
 | 
						_, ok := err.(ErrBadLink)
 | 
				
			||||||
 | 
						return ok
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// ErrUnsupportedVersion error when required git version not matched
 | 
					// ErrUnsupportedVersion error when required git version not matched
 | 
				
			||||||
type ErrUnsupportedVersion struct {
 | 
					type ErrUnsupportedVersion struct {
 | 
				
			||||||
	Required string
 | 
						Required string
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -167,6 +167,38 @@ func (te *TreeEntry) FollowLink() (*TreeEntry, error) {
 | 
				
			|||||||
	return target, nil
 | 
						return target, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// FollowLinks returns the entry ultimately pointed to by a symlink
 | 
				
			||||||
 | 
					func (te *TreeEntry) FollowLinks() (*TreeEntry, error) {
 | 
				
			||||||
 | 
						if !te.IsLink() {
 | 
				
			||||||
 | 
							return nil, ErrBadLink{te.Name(), "not a symlink"}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						entry := te
 | 
				
			||||||
 | 
						for i := 0; i < 999; i++ {
 | 
				
			||||||
 | 
							if entry.IsLink() {
 | 
				
			||||||
 | 
								next, err := entry.FollowLink()
 | 
				
			||||||
 | 
								if err != nil {
 | 
				
			||||||
 | 
									return nil, err
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								if next.ID == entry.ID {
 | 
				
			||||||
 | 
									return nil, ErrBadLink{
 | 
				
			||||||
 | 
										entry.Name(),
 | 
				
			||||||
 | 
										"recursive link",
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								entry = next
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								break
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if entry.IsLink() {
 | 
				
			||||||
 | 
							return nil, ErrBadLink{
 | 
				
			||||||
 | 
								te.Name(),
 | 
				
			||||||
 | 
								"too many levels of symbolic links",
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return entry, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// GetSubJumpablePathName return the full path of subdirectory jumpable ( contains only one directory )
 | 
					// GetSubJumpablePathName return the full path of subdirectory jumpable ( contains only one directory )
 | 
				
			||||||
func (te *TreeEntry) GetSubJumpablePathName() string {
 | 
					func (te *TreeEntry) GetSubJumpablePathName() string {
 | 
				
			||||||
	if te.IsSubModule() || !te.IsDir() {
 | 
						if te.IsSubModule() || !te.IsDir() {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -732,6 +732,7 @@ file_too_large = The file is too large to be shown.
 | 
				
			|||||||
video_not_supported_in_browser = Your browser does not support the HTML5 'video' tag.
 | 
					video_not_supported_in_browser = Your browser does not support the HTML5 'video' tag.
 | 
				
			||||||
audio_not_supported_in_browser = Your browser does not support the HTML5 'audio' tag.
 | 
					audio_not_supported_in_browser = Your browser does not support the HTML5 'audio' tag.
 | 
				
			||||||
stored_lfs = Stored with Git LFS
 | 
					stored_lfs = Stored with Git LFS
 | 
				
			||||||
 | 
					symbolic_link = Symbolic link
 | 
				
			||||||
commit_graph = Commit Graph
 | 
					commit_graph = Commit Graph
 | 
				
			||||||
blame = Blame
 | 
					blame = Blame
 | 
				
			||||||
normal_view = Normal View
 | 
					normal_view = Normal View
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -36,6 +36,83 @@ const (
 | 
				
			|||||||
	tplMigrating base.TplName = "repo/migrating"
 | 
						tplMigrating base.TplName = "repo/migrating"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type namedBlob struct {
 | 
				
			||||||
 | 
						name      string
 | 
				
			||||||
 | 
						isSymlink bool
 | 
				
			||||||
 | 
						blob      *git.Blob
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// FIXME: There has to be a more efficient way of doing this
 | 
				
			||||||
 | 
					func getReadmeFileFromPath(commit *git.Commit, treePath string) (*namedBlob, error) {
 | 
				
			||||||
 | 
						tree, err := commit.SubTree(treePath)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						entries, err := tree.ListEntries()
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var readmeFiles [4]*namedBlob
 | 
				
			||||||
 | 
						var exts = []string{".md", ".txt", ""} // sorted by priority
 | 
				
			||||||
 | 
						for _, entry := range entries {
 | 
				
			||||||
 | 
							if entry.IsDir() {
 | 
				
			||||||
 | 
								continue
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							for i, ext := range exts {
 | 
				
			||||||
 | 
								if markup.IsReadmeFile(entry.Name(), ext) {
 | 
				
			||||||
 | 
									if readmeFiles[i] == nil || base.NaturalSortLess(readmeFiles[i].name, entry.Blob().Name()) {
 | 
				
			||||||
 | 
										name := entry.Name()
 | 
				
			||||||
 | 
										isSymlink := entry.IsLink()
 | 
				
			||||||
 | 
										target := entry
 | 
				
			||||||
 | 
										if isSymlink {
 | 
				
			||||||
 | 
											target, err = entry.FollowLinks()
 | 
				
			||||||
 | 
											if err != nil && !git.IsErrBadLink(err) {
 | 
				
			||||||
 | 
												return nil, err
 | 
				
			||||||
 | 
											}
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
										if target != nil && (target.IsExecutable() || target.IsRegular()) {
 | 
				
			||||||
 | 
											readmeFiles[i] = &namedBlob{
 | 
				
			||||||
 | 
												name,
 | 
				
			||||||
 | 
												isSymlink,
 | 
				
			||||||
 | 
												target.Blob(),
 | 
				
			||||||
 | 
											}
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if markup.IsReadmeFile(entry.Name()) {
 | 
				
			||||||
 | 
								if readmeFiles[3] == nil || base.NaturalSortLess(readmeFiles[3].name, entry.Blob().Name()) {
 | 
				
			||||||
 | 
									name := entry.Name()
 | 
				
			||||||
 | 
									isSymlink := entry.IsLink()
 | 
				
			||||||
 | 
									if isSymlink {
 | 
				
			||||||
 | 
										entry, err = entry.FollowLinks()
 | 
				
			||||||
 | 
										if err != nil && !git.IsErrBadLink(err) {
 | 
				
			||||||
 | 
											return nil, err
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									if entry != nil && (entry.IsExecutable() || entry.IsRegular()) {
 | 
				
			||||||
 | 
										readmeFiles[3] = &namedBlob{
 | 
				
			||||||
 | 
											name,
 | 
				
			||||||
 | 
											isSymlink,
 | 
				
			||||||
 | 
											entry.Blob(),
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						var readmeFile *namedBlob
 | 
				
			||||||
 | 
						for _, f := range readmeFiles {
 | 
				
			||||||
 | 
							if f != nil {
 | 
				
			||||||
 | 
								readmeFile = f
 | 
				
			||||||
 | 
								break
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return readmeFile, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func renderDirectory(ctx *context.Context, treeLink string) {
 | 
					func renderDirectory(ctx *context.Context, treeLink string) {
 | 
				
			||||||
	tree, err := ctx.Repo.Commit.SubTree(ctx.Repo.TreePath)
 | 
						tree, err := ctx.Repo.Commit.SubTree(ctx.Repo.TreePath)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
@@ -65,25 +142,75 @@ func renderDirectory(ctx *context.Context, treeLink string) {
 | 
				
			|||||||
	// 3 for the extensions in exts[] in order
 | 
						// 3 for the extensions in exts[] in order
 | 
				
			||||||
	// the last one is for a readme that doesn't
 | 
						// the last one is for a readme that doesn't
 | 
				
			||||||
	// strictly match an extension
 | 
						// strictly match an extension
 | 
				
			||||||
	var readmeFiles [4]*git.Blob
 | 
						var readmeFiles [4]*namedBlob
 | 
				
			||||||
 | 
						var docsEntries [3]*git.TreeEntry
 | 
				
			||||||
	var exts = []string{".md", ".txt", ""} // sorted by priority
 | 
						var exts = []string{".md", ".txt", ""} // sorted by priority
 | 
				
			||||||
	for _, entry := range entries {
 | 
						for _, entry := range entries {
 | 
				
			||||||
		if entry.IsDir() {
 | 
							if entry.IsDir() {
 | 
				
			||||||
 | 
								lowerName := strings.ToLower(entry.Name())
 | 
				
			||||||
 | 
								switch lowerName {
 | 
				
			||||||
 | 
								case "docs":
 | 
				
			||||||
 | 
									if entry.Name() == "docs" || docsEntries[0] == nil {
 | 
				
			||||||
 | 
										docsEntries[0] = entry
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								case ".gitea":
 | 
				
			||||||
 | 
									if entry.Name() == ".gitea" || docsEntries[1] == nil {
 | 
				
			||||||
 | 
										docsEntries[1] = entry
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								case ".github":
 | 
				
			||||||
 | 
									if entry.Name() == ".github" || docsEntries[2] == nil {
 | 
				
			||||||
 | 
										docsEntries[2] = entry
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
			continue
 | 
								continue
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		for i, ext := range exts {
 | 
							for i, ext := range exts {
 | 
				
			||||||
			if markup.IsReadmeFile(entry.Name(), ext) {
 | 
								if markup.IsReadmeFile(entry.Name(), ext) {
 | 
				
			||||||
				readmeFiles[i] = entry.Blob()
 | 
									log.Debug("%s", entry.Name())
 | 
				
			||||||
 | 
									name := entry.Name()
 | 
				
			||||||
 | 
									isSymlink := entry.IsLink()
 | 
				
			||||||
 | 
									target := entry
 | 
				
			||||||
 | 
									if isSymlink {
 | 
				
			||||||
 | 
										target, err = entry.FollowLinks()
 | 
				
			||||||
 | 
										if err != nil && !git.IsErrBadLink(err) {
 | 
				
			||||||
 | 
											ctx.ServerError("FollowLinks", err)
 | 
				
			||||||
 | 
											return
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									log.Debug("%t", target == nil)
 | 
				
			||||||
 | 
									if target != nil && (target.IsExecutable() || target.IsRegular()) {
 | 
				
			||||||
 | 
										readmeFiles[i] = &namedBlob{
 | 
				
			||||||
 | 
											name,
 | 
				
			||||||
 | 
											isSymlink,
 | 
				
			||||||
 | 
											target.Blob(),
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if markup.IsReadmeFile(entry.Name()) {
 | 
							if markup.IsReadmeFile(entry.Name()) {
 | 
				
			||||||
			readmeFiles[3] = entry.Blob()
 | 
								name := entry.Name()
 | 
				
			||||||
 | 
								isSymlink := entry.IsLink()
 | 
				
			||||||
 | 
								if isSymlink {
 | 
				
			||||||
 | 
									entry, err = entry.FollowLinks()
 | 
				
			||||||
 | 
									if err != nil && !git.IsErrBadLink(err) {
 | 
				
			||||||
 | 
										ctx.ServerError("FollowLinks", err)
 | 
				
			||||||
 | 
										return
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								if entry != nil && (entry.IsExecutable() || entry.IsRegular()) {
 | 
				
			||||||
 | 
									readmeFiles[3] = &namedBlob{
 | 
				
			||||||
 | 
										name,
 | 
				
			||||||
 | 
										isSymlink,
 | 
				
			||||||
 | 
										entry.Blob(),
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	var readmeFile *git.Blob
 | 
						var readmeFile *namedBlob
 | 
				
			||||||
 | 
						readmeTreelink := treeLink
 | 
				
			||||||
	for _, f := range readmeFiles {
 | 
						for _, f := range readmeFiles {
 | 
				
			||||||
		if f != nil {
 | 
							if f != nil {
 | 
				
			||||||
			readmeFile = f
 | 
								readmeFile = f
 | 
				
			||||||
@@ -91,12 +218,31 @@ func renderDirectory(ctx *context.Context, treeLink string) {
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if ctx.Repo.TreePath == "" && readmeFile == nil {
 | 
				
			||||||
 | 
							for _, entry := range docsEntries {
 | 
				
			||||||
 | 
								if entry == nil {
 | 
				
			||||||
 | 
									continue
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								readmeFile, err = getReadmeFileFromPath(ctx.Repo.Commit, entry.GetSubJumpablePathName())
 | 
				
			||||||
 | 
								if err != nil {
 | 
				
			||||||
 | 
									ctx.ServerError("getReadmeFileFromPath", err)
 | 
				
			||||||
 | 
									return
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								if readmeFile != nil {
 | 
				
			||||||
 | 
									readmeFile.name = entry.Name() + "/" + readmeFile.name
 | 
				
			||||||
 | 
									readmeTreelink = treeLink + "/" + entry.GetSubJumpablePathName()
 | 
				
			||||||
 | 
									break
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if readmeFile != nil {
 | 
						if readmeFile != nil {
 | 
				
			||||||
		ctx.Data["RawFileLink"] = ""
 | 
							ctx.Data["RawFileLink"] = ""
 | 
				
			||||||
		ctx.Data["ReadmeInList"] = true
 | 
							ctx.Data["ReadmeInList"] = true
 | 
				
			||||||
		ctx.Data["ReadmeExist"] = true
 | 
							ctx.Data["ReadmeExist"] = true
 | 
				
			||||||
 | 
							ctx.Data["FileIsSymlink"] = readmeFile.isSymlink
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		dataRc, err := readmeFile.DataAsync()
 | 
							dataRc, err := readmeFile.blob.DataAsync()
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			ctx.ServerError("Data", err)
 | 
								ctx.ServerError("Data", err)
 | 
				
			||||||
			return
 | 
								return
 | 
				
			||||||
@@ -109,7 +255,7 @@ func renderDirectory(ctx *context.Context, treeLink string) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		isTextFile := base.IsTextFile(buf)
 | 
							isTextFile := base.IsTextFile(buf)
 | 
				
			||||||
		ctx.Data["FileIsText"] = isTextFile
 | 
							ctx.Data["FileIsText"] = isTextFile
 | 
				
			||||||
		ctx.Data["FileName"] = readmeFile.Name()
 | 
							ctx.Data["FileName"] = readmeFile.name
 | 
				
			||||||
		fileSize := int64(0)
 | 
							fileSize := int64(0)
 | 
				
			||||||
		isLFSFile := false
 | 
							isLFSFile := false
 | 
				
			||||||
		ctx.Data["IsLFSFile"] = false
 | 
							ctx.Data["IsLFSFile"] = false
 | 
				
			||||||
@@ -151,13 +297,13 @@ func renderDirectory(ctx *context.Context, treeLink string) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
				fileSize = meta.Size
 | 
									fileSize = meta.Size
 | 
				
			||||||
				ctx.Data["FileSize"] = meta.Size
 | 
									ctx.Data["FileSize"] = meta.Size
 | 
				
			||||||
				filenameBase64 := base64.RawURLEncoding.EncodeToString([]byte(readmeFile.Name()))
 | 
									filenameBase64 := base64.RawURLEncoding.EncodeToString([]byte(readmeFile.name))
 | 
				
			||||||
				ctx.Data["RawFileLink"] = fmt.Sprintf("%s%s.git/info/lfs/objects/%s/%s", setting.AppURL, ctx.Repo.Repository.FullName(), meta.Oid, filenameBase64)
 | 
									ctx.Data["RawFileLink"] = fmt.Sprintf("%s%s.git/info/lfs/objects/%s/%s", setting.AppURL, ctx.Repo.Repository.FullName(), meta.Oid, filenameBase64)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if !isLFSFile {
 | 
							if !isLFSFile {
 | 
				
			||||||
			fileSize = readmeFile.Size()
 | 
								fileSize = readmeFile.blob.Size()
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if isTextFile {
 | 
							if isTextFile {
 | 
				
			||||||
@@ -170,10 +316,10 @@ func renderDirectory(ctx *context.Context, treeLink string) {
 | 
				
			|||||||
				d, _ := ioutil.ReadAll(dataRc)
 | 
									d, _ := ioutil.ReadAll(dataRc)
 | 
				
			||||||
				buf = charset.ToUTF8WithFallback(append(buf, d...))
 | 
									buf = charset.ToUTF8WithFallback(append(buf, d...))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				if markupType := markup.Type(readmeFile.Name()); markupType != "" {
 | 
									if markupType := markup.Type(readmeFile.name); markupType != "" {
 | 
				
			||||||
					ctx.Data["IsMarkup"] = true
 | 
										ctx.Data["IsMarkup"] = true
 | 
				
			||||||
					ctx.Data["MarkupType"] = string(markupType)
 | 
										ctx.Data["MarkupType"] = string(markupType)
 | 
				
			||||||
					ctx.Data["FileContent"] = string(markup.Render(readmeFile.Name(), buf, treeLink, ctx.Repo.Repository.ComposeMetas()))
 | 
										ctx.Data["FileContent"] = string(markup.Render(readmeFile.name, buf, readmeTreelink, ctx.Repo.Repository.ComposeMetas()))
 | 
				
			||||||
				} else {
 | 
									} else {
 | 
				
			||||||
					ctx.Data["IsRenderedHTML"] = true
 | 
										ctx.Data["IsRenderedHTML"] = true
 | 
				
			||||||
					ctx.Data["FileContent"] = strings.Replace(
 | 
										ctx.Data["FileContent"] = strings.Replace(
 | 
				
			||||||
@@ -218,6 +364,7 @@ func renderFile(ctx *context.Context, entry *git.TreeEntry, treeLink, rawLink st
 | 
				
			|||||||
	ctx.Data["Title"] = ctx.Data["Title"].(string) + " - " + ctx.Repo.TreePath + " at " + ctx.Repo.BranchName
 | 
						ctx.Data["Title"] = ctx.Data["Title"].(string) + " - " + ctx.Repo.TreePath + " at " + ctx.Repo.BranchName
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	fileSize := blob.Size()
 | 
						fileSize := blob.Size()
 | 
				
			||||||
 | 
						ctx.Data["FileIsSymlink"] = entry.IsLink()
 | 
				
			||||||
	ctx.Data["FileSize"] = fileSize
 | 
						ctx.Data["FileSize"] = fileSize
 | 
				
			||||||
	ctx.Data["FileName"] = blob.Name()
 | 
						ctx.Data["FileName"] = blob.Name()
 | 
				
			||||||
	ctx.Data["HighlightClass"] = highlight.FileNameToHighlightClass(blob.Name())
 | 
						ctx.Data["HighlightClass"] = highlight.FileNameToHighlightClass(blob.Name())
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,10 +2,19 @@
 | 
				
			|||||||
	<h4 class="file-header ui top attached header">
 | 
						<h4 class="file-header ui top attached header">
 | 
				
			||||||
		<div class="file-header-left">
 | 
							<div class="file-header-left">
 | 
				
			||||||
			{{if .ReadmeInList}}
 | 
								{{if .ReadmeInList}}
 | 
				
			||||||
				<i class="book icon"></i>
 | 
									{{if .FileIsSymlink}}
 | 
				
			||||||
 | 
										<i class="icons"><i class="book icon"></i><i class="bottom left corner tiny inverted share icon"></i></i>
 | 
				
			||||||
 | 
									{{else}}
 | 
				
			||||||
 | 
										<i class="book icon"></i>
 | 
				
			||||||
 | 
									{{end}}
 | 
				
			||||||
				<strong>{{.FileName}}</strong>
 | 
									<strong>{{.FileName}}</strong>
 | 
				
			||||||
			{{else}}
 | 
								{{else}}
 | 
				
			||||||
				<div class="file-info text grey normal mono">
 | 
									<div class="file-info text grey normal mono">
 | 
				
			||||||
 | 
										{{if .FileIsSymlink}}
 | 
				
			||||||
 | 
											<div class="file-info-entry">
 | 
				
			||||||
 | 
												{{.i18n.Tr "repo.symbolic_link"}}
 | 
				
			||||||
 | 
											</div>
 | 
				
			||||||
 | 
										{{end}}
 | 
				
			||||||
					{{if .NumLinesSet}}
 | 
										{{if .NumLinesSet}}
 | 
				
			||||||
						<div class="file-info-entry">
 | 
											<div class="file-info-entry">
 | 
				
			||||||
							{{.NumLines}} {{.i18n.Tr (TrN .i18n.Lang .NumLines "repo.line" "repo.lines") }}
 | 
												{{.NumLines}} {{.i18n.Tr (TrN .i18n.Lang .NumLines "repo.line" "repo.lines") }}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -381,6 +381,14 @@
 | 
				
			|||||||
                    font-size: 1em;
 | 
					                    font-size: 1em;
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                .small.icon {
 | 
				
			||||||
 | 
					                    font-size: 0.75em;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                .tiny.icon {
 | 
				
			||||||
 | 
					                    font-size: 0.5em;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                .file-actions {
 | 
					                .file-actions {
 | 
				
			||||||
                    margin-bottom: -5px;
 | 
					                    margin-bottom: -5px;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user