Skip to content

Commit 12445b0

Browse files
committed
feat: add custom icons to content types in dir listing, add .log support in contenttypes header.
1 parent d2711ec commit 12445b0

File tree

3 files changed

+106
-3
lines changed

3 files changed

+106
-3
lines changed

example/files/empty.html

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8">
5+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
6+
<title>Document</title>
7+
</head>
8+
<body>
9+
empty document, what did you expect?
10+
</body>
11+
</html>

src/include/contentTypes.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ inline const char *guessContentType(const char *path)
2020
return "image/jpeg";
2121
if (strcmp(dot, ".gif") == 0)
2222
return "image/gif";
23-
if (strcmp(dot, ".txt") == 0)
23+
if (strcmp(dot, ".txt") == 0 || strcmp(dot, ".log") == 0)
2424
return "text/plain";
2525
if (strcmp(dot, ".svg") == 0)
2626
return "image/svg+xml";

src/returnDirListing.cpp

Lines changed: 94 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,61 @@ static const char *homeSvg =
3535
"<path d=\"M15 21v-8a1 1 0 0 0-1-1h-4a1 1 0 0 0-1 1v8\"/>"
3636
"<path d=\"M3 10a2 2 0 0 1 .709-1.528l7-5.999a2 2 0 0 1 2.582 0l7 5.999A2 2 0 0 1 21 10v9a2 2 0 0 1-2 2H5a2 2 0 0 1-2 2z\"/></svg>";
3737

38+
static const char *upFolderSvg =
39+
"<svg xmlns=\"http://www.w3.org/2000/svg\" "
40+
"width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"%23e0e0e0\" stroke-width=\"2\" "
41+
"stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"lucide lucide-folder-up-icon lucide-folder-up\">"
42+
"<path d=\"M20 20a2 2 0 0 0 2-2V8a2 2 0 0 0-2-2h-7.9a2 2 0 0 1-1.69-.9L9.6 3.9A2 2 0 0 0 7.93 3H4a2 2 0 0 0-2 2v13a2 2 0 0 0 2 2Z\"/>"
43+
"<path d=\"M12 10v6\"/>"
44+
"<path d=\"m9 13 3-3 3 3\"/></svg>";
45+
46+
static const char *filmSvg =
47+
"<svg xmlns=\"http://www.w3.org/2000/svg\" "
48+
"width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"%23e0e0e0\" stroke-width=\"2\" "
49+
"stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"lucide lucide-film-icon lucide-film\">"
50+
"<rect width=\"18\" height=\"18\" x=\"3\" y=\"3\" rx=\"2\"/>"
51+
"<path d=\"M7 3v18\"/>"
52+
"<path d=\"M3 7.5h4\"/>"
53+
"<path d=\"M3 12h18\"/>"
54+
"<path d=\"M3 16.5h4\"/>"
55+
"<path d=\"M17 3v18\"/>"
56+
"<path d=\"M17 7.5h4\"/>"
57+
"<path d=\"M17 16.5h4\"/></svg>";
58+
59+
static const char *imageSvg =
60+
"<svg xmlns=\"http://www.w3.org/2000/svg\" "
61+
"width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"%23e0e0e0\" stroke-width=\"2\" "
62+
"stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"lucide lucide-file-image-icon lucide-file-image\">"
63+
"<path d=\"M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z\"/>"
64+
"<path d=\"M14 2v4a2 2 0 0 0 2 2h4\"/>"
65+
"<circle cx=\"10\" cy=\"12\" r=\"2\"/>"
66+
"<path d=\"m20 17-1.296-1.296a2.41 2.41 0 0 0-3.408 0L9 22\"/></svg>";
67+
68+
static const char *textfileSvg =
69+
"<svg xmlns=\"http://www.w3.org/2000/svg\" "
70+
"width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"%23e0e0e0\" stroke-width=\"2\" "
71+
"stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"lucide lucide-file-text-icon lucide-file-text\">"
72+
"<path d=\"M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z\"/>"
73+
"<path d=\"M14 2v4a2 2 0 0 0 2 2h4\"/>"
74+
"<path d=\"M10 9H8\"/>"
75+
"<path d=\"M16 13H8\"/>"
76+
"<path d=\"M16 17H8\"/></svg>";
77+
78+
static const char *activitySvg =
79+
"<svg xmlns=\"http://www.w3.org/2000/svg\" "
80+
"width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"%23e0e0e0\" stroke-width=\"2\" "
81+
"stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"lucide lucide-activity-icon lucide-activity\">"
82+
"<path d=\"M22 12h-2.48a2 2 0 0 0-1.93 1.46l-2.35 8.36a.25.25 0 0 1-.48 0L9.24 2.18a.25.25 0 0 0-.48 0l-2.35 8.36A2 2 0 0 1 4.49 12H2\"/></svg>";
83+
84+
static const char *codexmlSvg =
85+
"<svg xmlns=\"http://www.w3.org/2000/svg\" "
86+
"width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"%23e0e0e0\" stroke-width=\"2\" "
87+
"stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"lucide lucide-code-xml-icon lucide-code-xml\">"
88+
"<path d=\"m18 16 4-4-4-4\"/>"
89+
"<path d=\"m6 8-4 4 4 4\"/>"
90+
"<path d=\"m14.5 4-5 16\"/>"
91+
"</svg>";
92+
3893
static const std::string styling =
3994
"<style>"
4095
"body { font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; margin: 20px; background-color: #2d2d2d; color: #e0e0e0; }"
@@ -55,6 +110,18 @@ static const std::string styling =
55110
std::string(fileSvg) + "'); vertical-align: middle; margin-right: 8px; color: #f0f0f0; }"
56111
".home:before { content: url('data:image/svg+xml;utf8," +
57112
std::string(homeSvg) + "'); vertical-align: middle; margin-right: 8px; color: #f0f0f0; }"
113+
".upfolder:before { content: url('data:image/svg+xml;utf8," +
114+
std::string(upFolderSvg) + "'); vertical-align: middle; margin-right: 8px; color: #f0f0f0; }"
115+
".film:before { content: url('data:image/svg+xml;utf8," +
116+
std::string(filmSvg) + "'); vertical-align: middle; margin-right: 8px; color: #f0f0f0; }"
117+
".image:before { content: url('data:image/svg+xml;utf8," +
118+
std::string(imageSvg) + "'); vertical-align: middle; margin-right: 8px; color: #f0f0f0; }"
119+
".textfile:before { content: url('data:image/svg+xml;utf8," +
120+
std::string(textfileSvg) + "'); vertical-align: middle; margin-right: 8px; color: #f0f0f0; }"
121+
".activity:before { content: url('data:image/svg+xml;utf8," +
122+
std::string(activitySvg) + "'); vertical-align: middle; margin-right: 8px; color: #f0f0f0; }"
123+
".codexml:before { content: url('data:image/svg+xml;utf8," +
124+
std::string(codexmlSvg) + "'); vertical-align: middle; margin-right: 8px; color: #f0f0f0; }"
58125
"</style>";
59126
60127
static const std::string pageHeader =
@@ -65,6 +132,28 @@ static const char *pageFooter = "</table></body>"
65132
"<footer><p>Powered by faucet</p></footer>"
66133
"</html>";
67134

135+
static std::string getFileTypeClass(const std::string &filename) {
136+
// determine file type by extension for icon
137+
size_t dotPos = filename.rfind('.');
138+
if (dotPos == std::string::npos || dotPos == filename.length() - 1)
139+
return "file"; // no extension
140+
141+
std::string ext = filename.substr(dotPos + 1);
142+
std::transform(ext.begin(), ext.end(), ext.begin(), [](unsigned char c) { return std::tolower(c); });
143+
144+
if (ext == "mp4" || ext == "mkv" || ext == "avi" || ext == "mov" || ext == "wmv" || ext == "flv" || ext == "webm")
145+
return "film";
146+
if (ext == "jpg" || ext == "jpeg" || ext == "png" || ext == "gif" || ext == "bmp" || ext == "svg" || ext == "webp" || ext == "tiff")
147+
return "image";
148+
if (ext == "txt" || ext == "md" || ext == "log" || ext == "csv" || ext == "json" || ext == "xml" || ext == "ini" || ext == "cfg")
149+
return "textfile";
150+
if (ext == "html" || ext == "htm" || ext == "css" || ext == "js" || ext == "cpp" || ext == "h" || ext == "hpp" || ext == "c" || ext == "java" || ext == "py" || ext == "rb" || ext == "go")
151+
return "codexml";
152+
if (ext == "log")
153+
return "activity";
154+
return "file"; // default
155+
}
156+
68157
void returnDirListing(int client_fd,
69158
const std::string &siteDir,
70159
const std::string &relPath,
@@ -132,7 +221,7 @@ void returnDirListing(int client_fd,
132221
if (!relPath.empty())
133222
{
134223
body += "<tr><td><a href=\"/\" class=\"home\">Home (/)</a></td><td></td><td></td></tr>"; // root
135-
body += "<tr><td><a href=\"../\" class=\"directory\">Parent Directory (../)</a></td><td></td><td></td></tr>"; // parent dir
224+
body += "<tr><td><a href=\"../\" class=\"upfolder\">Parent Directory (../)</a></td><td></td><td></td></tr>"; // parent dir
136225
}
137226

138227
for (auto &e : entries)
@@ -159,7 +248,7 @@ void returnDirListing(int client_fd,
159248
}
160249
else
161250
{
162-
body += "\" class=\"file\">" + display + "</a></td>";
251+
body += "\" class=\"" + getFileTypeClass(e) + "\">" + display + "</a></td>";
163252
}
164253

165254
if (!isDir)
@@ -192,6 +281,9 @@ void returnDirListing(int client_fd,
192281
strftime(timebuf, sizeof(timebuf), "%Y-%m-%d %H:%M", tm_info);
193282
body += "<td>" + std::string(timebuf) + "</td>";
194283
}
284+
} else
285+
{
286+
body += "<td></td><td></td>"; // empty size and date for directories
195287
}
196288

197289
// close

0 commit comments

Comments
 (0)