Static content, init/setup tweaks, some cleanup

This commit is contained in:
Bob Farrell 2024-01-21 19:00:41 +00:00
parent 3223146e30
commit b77ea5fd51
28 changed files with 474 additions and 143 deletions

View File

@ -21,6 +21,7 @@ If you are interested in _Jetzig_ you will probably find these tools interesting
* :white_check_mark: Sessions. * :white_check_mark: Sessions.
* :white_check_mark: Cookies. * :white_check_mark: Cookies.
* :white_check_mark: Error handling. * :white_check_mark: Error handling.
* :x: Static content from /public directory.
* :x: Headers (available but not yet wrapped). * :x: Headers (available but not yet wrapped).
* :x: Param/JSON payload parsing/abstracting. * :x: Param/JSON payload parsing/abstracting.
* :x: Development-mode responses for debugging. * :x: Development-mode responses for debugging.

View File

@ -39,6 +39,11 @@ objects=(
'src/main.zig' 'src/main.zig'
'src/app/views/index.zig' 'src/app/views/index.zig'
'src/app/views/index.zmpl' 'src/app/views/index.zmpl'
'src/app/views/quotes.zig'
'src/app/views/quotes/get.zmpl'
'src/app/config/quotes.json'
'public/jetzig.png'
'.gitignore'
) )
for object in "${objects[@]}" for object in "${objects[@]}"
@ -57,8 +62,10 @@ do
fi fi
done done
sed -i.bak -e "s,%%project_name%%,${project},g" 'src/build.zig' && rm build.zig.bak sed -i.bak -e "s,%%project_name%%,${project},g" "${project_path}/build.zig"
sed -i.bak -e "s,%%project_name%%,${project},g" 'src/build.zig.zon' && rm build.zig.zon.bak rm "${project_path}/build.zig.bak"
sed -i.bak -e "s,%%project_name%%,${project},g" "${project_path}/build.zig.zon"
rm "${project_path}/build.zig.zon.bak"
echo echo
echo "Finished creating new project in: ${project_path}" echo "Finished creating new project in: ${project_path}"

BIN
public/jetzig.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

102
src/app/config/quotes.json Normal file
View File

@ -0,0 +1,102 @@
[{"quote": "Life isnt about getting and having, its about giving and being.", "author": "Kevin Kruse"},
{"quote": "Whatever the mind of man can conceive and believe, it can achieve.", "author": "Napoleon Hill"},
{"quote": "Strive not to be a success, but rather to be of value.", "author": "Albert Einstein"},
{"quote": "Two roads diverged in a wood, and I—I took the one less traveled by, And that has made all the difference.", "author": "Robert Frost"},
{"quote": "I attribute my success to this: I never gave or took any excuse.", "author": "Florence Nightingale"},
{"quote": "You miss 100% of the shots you dont take.", "author": "Wayne Gretzky"},
{"quote": "Ive missed more than 9000 shots in my career. Ive lost almost 300 games. 26 times Ive been trusted to take the game winning shot and missed. Ive failed over and over and over again in my life. And that is why I succeed.", "author": "Michael Jordan"},
{"quote": "The most difficult thing is the decision to act, the rest is merely tenacity.", "author": "Amelia Earhart"},
{"quote": "Every strike brings me closer to the next home run.", "author": "Babe Ruth"},
{"quote": "Definiteness of purpose is the starting point of all achievement.", "author": "W. Clement Stone"},
{"quote": "We must balance conspicuous consumption with conscious capitalism.", "author": "Kevin Kruse"},
{"quote": "Life is what happens to you while youre busy making other plans.", "author": "John Lennon"},
{"quote": "We become what we think about.", "author": "Earl Nightingale"},
{"quote": "14.Twenty years from now you will be more disappointed by the things that you didnt do than by the ones you did do, so throw off the bowlines, sail away from safe harbor, catch the trade winds in your sails. Explore, Dream, Discover.", "author": "Mark Twain"},
{"quote": "15.Life is 10% what happens to me and 90% of how I react to it.", "author": "Charles Swindoll"},
{"quote": "The most common way people give up their power is by thinking they dont have any.", "author": "Alice Walker"},
{"quote": "The mind is everything. What you think you become.", "author": "Buddha"},
{"quote": "The best time to plant a tree was 20 years ago. The second best time is now.", "author": "Chinese Proverb"},
{"quote": "An unexamined life is not worth living.", "author": "Socrates"},
{"quote": "Eighty percent of success is showing up.", "author": "Woody Allen"},
{"quote": "Your time is limited, so dont waste it living someone elses life.", "author": "Steve Jobs"},
{"quote": "Winning isnt everything, but wanting to win is.", "author": "Vince Lombardi"},
{"quote": "I am not a product of my circumstances. I am a product of my decisions.", "author": "Stephen Covey"},
{"quote": "Every child is an artist. The problem is how to remain an artist once he grows up.", "author": "Pablo Picasso"},
{"quote": "You can never cross the ocean until you have the courage to lose sight of the shore.", "author": "Christopher Columbus"},
{"quote": "Ive learned that people will forget what you said, people will forget what you did, but people will never forget how you made them feel.", "author": "Maya Angelou"},
{"quote": "Either you run the day, or the day runs you.", "author": "Jim Rohn"},
{"quote": "Whether you think you can or you think you cant, youre right.", "author": "Henry Ford"},
{"quote": "The two most important days in your life are the day you are born and the day you find out why.", "author": "Mark Twain"},
{"quote": "Whatever you can do, or dream you can, begin it. Boldness has genius, power and magic in it.", "author": "Johann Wolfgang von Goethe"},
{"quote": "The best revenge is massive success.", "author": "Frank Sinatra"},
{"quote": "People often say that motivation doesnt last. Well, neither does bathing. Thats why we recommend it daily.", "author": "Zig Ziglar"},
{"quote": "Life shrinks or expands in proportion to ones courage.", "author": "Anais Nin"},
{"quote": "If you hear a voice within you say “you cannot paint,” then by all means paint and that voice will be silenced.", "author": "Vincent Van Gogh"},
{"quote": "There is only one way to avoid criticism: do nothing, say nothing, and be nothing.", "author": "Aristotle"},
{"quote": "Ask and it will be given to you; search, and you will find; knock and the door will be opened for you.", "author": "Jesus"},
{"quote": "The only person you are destined to become is the person you decide to be.", "author": "Ralph Waldo Emerson"},
{"quote": "Go confidently in the direction of your dreams. Live the life you have imagined.", "author": "Henry David Thoreau"},
{"quote": "When I stand before God at the end of my life, I would hope that I would not have a single bit of talent left and could say, I used everything you gave me.", "author": "Erma Bombeck"},
{"quote": "Few things can help an individual more than to place responsibility on him, and to let him know that you trust him.", "author": "Booker T. Washington"},
{"quote": "Certain things catch your eye, but pursue only those that capture the heart.", "author": " Ancient Indian Proverb"},
{"quote": "Believe you can and youre halfway there.", "author": "Theodore Roosevelt"},
{"quote": "Everything youve ever wanted is on the other side of fear.", "author": "George Addair"},
{"quote": "We can easily forgive a child who is afraid of the dark; the real tragedy of life is when men are afraid of the light.", "author": "Plato"},
{"quote": "Teach thy tongue to say, “I do not know,” and thous shalt progress.", "author": "Maimonides"},
{"quote": "Start where you are. Use what you have. Do what you can.", "author": "Arthur Ashe"},
{"quote": "When I was 5 years old, my mother always told me that happiness was the key to life. When I went to school, they asked me what I wanted to be when I grew up. I wrote down happy. They told me I didnt understand the assignment, and I told them they didnt understand life.", "author": "John Lennon"},
{"quote": "Fall seven times and stand up eight.", "author": "Japanese Proverb"},
{"quote": "When one door of happiness closes, another opens, but often we look so long at the closed door that we do not see the one that has been opened for us.", "author": "Helen Keller"},
{"quote": "Everything has beauty, but not everyone can see.", "author": "Confucius"},
{"quote": "How wonderful it is that nobody need wait a single moment before starting to improve the world.", "author": "Anne Frank"},
{"quote": "When I let go of what I am, I become what I might be.", "author": "Lao Tzu"},
{"quote": "Life is not measured by the number of breaths we take, but by the moments that take our breath away.", "author": "Maya Angelou"},
{"quote": "Happiness is not something readymade. It comes from your own actions.", "author": "Dalai Lama"},
{"quote": "If youre offered a seat on a rocket ship, dont ask what seat! Just get on.", "author": "Sheryl Sandberg"},
{"quote": "First, have a definite, clear practical ideal; a goal, an objective. Second, have the necessary means to achieve your ends; wisdom, money, materials, and methods. Third, adjust all your means to that end.", "author": "Aristotle"},
{"quote": "If the wind will not serve, take to the oars.", "author": "Latin Proverb"},
{"quote": "You cant fall if you dont climb. But theres no joy in living your whole life on the ground.", "author": "Unknown"},
{"quote": "We must believe that we are gifted for something, and that this thing, at whatever cost, must be attained.", "author": "Marie Curie"},
{"quote": "Too many of us are not living our dreams because we are living our fears.", "author": "Les Brown"},
{"quote": "Challenges are what make life interesting and overcoming them is what makes life meaningful.", "author": "Joshua J. Marine"},
{"quote": "If you want to lift yourself up, lift up someone else.", "author": "Booker T. Washington"},
{"quote": "I have been impressed with the urgency of doing. Knowing is not enough; we must apply. Being willing is not enough; we must do.", "author": "Leonardo da Vinci"},
{"quote": "Limitations live only in our minds. But if we use our imaginations, our possibilities become limitless.", "author": "Jamie Paolinetti"},
{"quote": "You take your life in your own hands, and what happens? A terrible thing, no one to blame.", "author": "Erica Jong"},
{"quote": "Whats money? A man is a success if he gets up in the morning and goes to bed at night and in between does what he wants to do.", "author": "Bob Dylan"},
{"quote": "I didnt fail the test. I just found 100 ways to do it wrong.", "author": "Benjamin Franklin"},
{"quote": "In order to succeed, your desire for success should be greater than your fear of failure.", "author": "Bill Cosby"},
{"quote": "A person who never made a mistake never tried anything new.", "author": " Albert Einstein"},
{"quote": "The person who says it cannot be done should not interrupt the person who is doing it.", "author": "Chinese Proverb"},
{"quote": "There are no traffic jams along the extra mile.", "author": "Roger Staubach"},
{"quote": "It is never too late to be what you might have been.", "author": "George Eliot"},
{"quote": "You become what you believe.", "author": "Oprah Winfrey"},
{"quote": "I would rather die of passion than of boredom.", "author": "Vincent van Gogh"},
{"quote": "A truly rich man is one whose children run into his arms when his hands are empty.", "author": "Unknown"},
{"quote": "It is not what you do for your children, but what you have taught them to do for themselves, that will make them successful human beings.", "author": "Ann Landers"},
{"quote": "If you want your children to turn out well, spend twice as much time with them, and half as much money.", "author": "Abigail Van Buren"},
{"quote": "Build your own dreams, or someone else will hire you to build theirs.", "author": "Farrah Gray"},
{"quote": "The battles that count arent the ones for gold medals. The struggles within yourselfthe invisible battles inside all of usthats where its at.", "author": "Jesse Owens"},
{"quote": "Education costs money. But then so does ignorance.", "author": "Sir Claus Moser"},
{"quote": "I have learned over the years that when ones mind is made up, this diminishes fear.", "author": "Rosa Parks"},
{"quote": "It does not matter how slowly you go as long as you do not stop.", "author": "Confucius"},
{"quote": "If you look at what you have in life, youll always have more. If you look at what you dont have in life, youll never have enough.", "author": "Oprah Winfrey"},
{"quote": "Remember that not getting what you want is sometimes a wonderful stroke of luck.", "author": "Dalai Lama"},
{"quote": "You cant use up creativity. The more you use, the more you have.", "author": "Maya Angelou"},
{"quote": "Dream big and dare to fail.", "author": "Norman Vaughan"},
{"quote": "Our lives begin to end the day we become silent about things that matter.", "author": "Martin Luther King Jr."},
{"quote": "Do what you can, where you are, with what you have.", "author": "Teddy Roosevelt"},
{"quote": "If you do what youve always done, youll get what youve always gotten.", "author": "Tony Robbins"},
{"quote": "Dreaming, after all, is a form of planning.", "author": "Gloria Steinem"},
{"quote": "Its your place in the world; its your life. Go on and do all you can with it, and make it the life you want to live.", "author": "Mae Jemison"},
{"quote": "You may be disappointed if you fail, but you are doomed if you dont try.", "author": "Beverly Sills"},
{"quote": "Remember no one can make you feel inferior without your consent.", "author": "Eleanor Roosevelt"},
{"quote": "Life is what we make it, always has been, always will be.", "author": "Grandma Moses"},
{"quote": "The question isnt who is going to let me; its who is going to stop me.", "author": "Ayn Rand"},
{"quote": "When everything seems to be going against you, remember that the airplane takes off against the wind, not with it.", "author": "Henry Ford"},
{"quote": "Its not the years in your life that count. Its the life in your years.", "author": "Abraham Lincoln"},
{"quote": "Change your thoughts and you change your world.", "author": "Norman Vincent Peale"},
{"quote": "Either write something worth reading or do something worth writing.", "author": "Benjamin Franklin"},
{"quote": "Nothing is impossible, the word itself says, “Im possible!”", "author": "Audrey Hepburn"},
{"quote": "The only way to do great work is to love what you do.", "author": "Steve Jobs"},
{"quote": "If you can dream it, you can achieve it.", "author": "Zig Ziglar"}]

View File

@ -1,53 +0,0 @@
const std = @import("std");
const root = @import("root");
const Request = root.jetzig.http.Request;
const Data = root.jetzig.data.Data;
const View = root.jetzig.views.View;
pub fn index(request: *Request, data: *Data) anyerror!View {
var object = try data.object();
try request.session.put("foo", data.string("bar"));
try object.put("message", data.string("hello there"));
try object.put("foo", data.string("foo lookup"));
try object.put("bar", data.string("bar lookup"));
try object.put("session_value", (try request.session.get("foo")).?);
return request.render(.ok);
}
pub fn get(id: []const u8, request: *Request, data: *Data) anyerror!View {
var object = try data.object();
try request.session.put("foo", data.string("bar"));
try object.put("session_value", (try request.session.get("foo")).?);
try object.put("message", data.string("hello there"));
try object.put("other_message", data.string("hello again"));
try object.put("an_integer", data.integer(10));
try object.put("a_float", data.float(1.345));
try object.put("a_boolean", data.boolean(true));
try object.put("Null", data.Null);
try object.put("a_random_integer", data.integer(std.crypto.random.int(u8)));
try object.put("resource_id", data.string(id));
var nested_object = try data.object();
try nested_object.put("nested key", data.string("nested value"));
try object.put("other_message", nested_object.*);
return request.render(.ok);
}
pub fn patch(id: []const u8, request: *Request, data: *Data) anyerror!View {
var object = try data.object();
const integer = std.crypto.random.int(u8);
try object.put("message", data.string("hello there"));
try object.put("other_message", data.string("hello again"));
try object.put("other_message", data.integer(integer));
try object.put("id", data.string(id));
return request.render(.ok);
}

View File

@ -1,2 +0,0 @@
<span>{.resource_id}</span>
<span>{.session_value}</span>

View File

@ -1,14 +0,0 @@
if (std.mem.eql(u8, try zmpl.getValueString("message"), "hello there")) {
const foo = "foo const";
const bar = "bar const";
inline for (1..4) |index| {
<div>Hello {:foo}!</div>
<div>Hello {:bar}!</div>
<div>Hello {:index}!</div>
<div>Hello {.foo}!</div>
<div>Hello {.bar}!</div>
}
} else {
<div>Unexpected message</div>
}

View File

@ -1,11 +1,27 @@
<script src="https://unpkg.com/htmx.org@1.9.10"></script> <html>
<head>
<script src="https://unpkg.com/htmx.org@1.9.10"></script>
<div hx-get="/options/latest" hx-trigger="every 1s"></div> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="https://cdn.tailwindcss.com"></script>
</head>
<body>
<div class="text-center pt-10 m-auto">
<div><img class="p-3 mx-auto" src="/jetzig.png" /></div>
inline for (0..10) |index| {
<div> <div>
<button hx-trigger="click" hx-put="/options/{:index}" hx-swap="innerHTML" hx-target="#option">Option #{:index}</option> <h1 class="text-3xl text-center p-3 pb-6 font-bold">Welcome to Jetzig!</h1>
</div> </div>
}
<div id="option">Select an option.</div> <button hx-get="/quotes/random" hx-trigger="click" hx-target="#quote" class="bg-[#39b54a] text-white font-bold py-2 px-4 rounded">Click Me</button>
<div id="quote" class="p-7 mx-auto w-1/2">
<div hx-get="/quotes/init" hx-trigger="load"></div>
</div>
<div>Take a look at the <span class="font-mono">src/app/</span> directory to see how this application works.</div>
<div>Visit <a class="font-bold text-[#39b54a]" href="https://www.jetzig.dev/">jetzig.dev</a> to get started.</div>
</div>
</body>
</html>

View File

@ -1,44 +0,0 @@
const std = @import("std");
const root = @import("root");
const Request = root.jetzig.http.Request;
const Data = root.jetzig.data.Data;
const View = root.jetzig.views.View;
pub fn put(id: []const u8, request: *Request, data: *Data) anyerror!View {
try request.session.put("option", data.string(id));
var object = try data.object();
try object.put("option", data.string(id));
const count = try request.session.get("count");
if (count) |value| {
if (value == .integer) {
try request.session.put("count", data.integer(value.integer.value + 1));
try object.put("count", data.integer(value.integer.value + 1));
} else {
return error.InvalidSessionData;
}
} else {
try request.session.put("count", data.integer(0));
try object.put("count", data.integer(0));
}
return request.render(.ok);
}
pub fn get(id: []const u8, request: *Request, data: *Data) anyerror!View {
if (std.mem.eql(u8, id, "latest")) {
var object = try data.object();
const count = try request.session.get("count");
if (count) |value| {
if (value == .integer) {
try object.put("count", data.integer(value.integer.value + 1));
} else {
try object.put("count", data.integer(0));
}
} else {
try object.put("count", data.integer(0));
}
}
return request.render(.ok);
}

View File

@ -1 +0,0 @@
<div>Number of times clicked: {.count}</div>

View File

@ -1 +0,0 @@
<div>You chose option {.option}</div>

34
src/app/views/quotes.zig Normal file
View File

@ -0,0 +1,34 @@
const std = @import("std");
const jetzig = @import("jetzig");
const Request = jetzig.http.Request;
const Data = jetzig.data.Data;
const View = jetzig.views.View;
pub fn get(id: []const u8, request: *Request, data: *Data) anyerror!View {
var body = try data.object();
const random_quote = try randomQuote(request.allocator);
if (std.mem.eql(u8, id, "random")) {
try body.put("quote", data.string(random_quote.quote));
try body.put("author", data.string(random_quote.author));
} else {
try body.put("quote", data.string("If you can dream it, you can achieve it."));
try body.put("author", data.string("Zig Ziglar"));
}
return request.render(.ok);
}
const Quote = struct {
quote: []const u8,
author: []const u8,
};
// Quotes taken from: https://gist.github.com/natebass/b0a548425a73bdf8ea5c618149fe1fce
fn randomQuote(allocator: std.mem.Allocator) !Quote {
const json = try std.fs.cwd().readFileAlloc(allocator, "src/app/config/quotes.json", 12684);
const quotes = try std.json.parseFromSlice([]Quote, allocator, json, .{});
return quotes.value[std.crypto.random.intRangeLessThan(usize, 0, quotes.value.len)];
}

View File

@ -0,0 +1,2 @@
<div>"{.quote}"</div>
<div><b>--{.author}</b></div>

View File

@ -1,5 +1,5 @@
pub const routes = .{ pub const routes = .{
@import("foo/bar/baz.zig"), @import("users.zig"),
@import("quotes.zig"),
@import("index.zig"), @import("index.zig"),
@import("options.zig"),
}; };

15
src/app/views/users.zig Normal file
View File

@ -0,0 +1,15 @@
const jetzig = @import("jetzig");
const Request = jetzig.http.Request;
const Data = jetzig.data.Data;
const View = jetzig.views.View;
pub fn get(id: []const u8, request: *Request, data: *Data) anyerror!View {
var user = try data.object();
try user.put("email", data.string("user@example.com"));
try user.put("name", data.string("Ziggy Ziguana"));
try user.put("id", data.string(id));
return request.render(.ok);
}

View File

@ -0,0 +1,8 @@
<div>
if (std.crypto.random.int(u1) == 1) {
<span>User won the coin toss!</span>
}
<span>ID: {.id}</span>
<span>Name: {.name}</span>
<span>Email: {.email}</span>
</div>

View File

@ -3,8 +3,6 @@
// This file should _not_ be stored in version control. // This file should _not_ be stored in version control.
pub const templates = struct { pub const templates = struct {
pub const index = @import(".index.zmpl.compiled.zig"); pub const index = @import(".index.zmpl.compiled.zig");
pub const foo_bar_baz_index = @import("foo/bar/baz/.index.zmpl.compiled.zig"); pub const quotes_get = @import("quotes/.get.zmpl.compiled.zig");
pub const foo_bar_baz_get = @import("foo/bar/baz/.get.zmpl.compiled.zig"); pub const users_get = @import("users/.get.zmpl.compiled.zig");
pub const options_put = @import("options/.put.zmpl.compiled.zig");
pub const options_get = @import("options/.get.zmpl.compiled.zig");
}; };

2
src/init/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
# Compiled Zmpl views:
src/app/views/**/*.compiled.zig

View File

@ -18,6 +18,19 @@ pub fn build(b: *std.Build) !void {
exe.addModule("jetzig", jetzig.module("jetzig")); exe.addModule("jetzig", jetzig.module("jetzig"));
try b.modules.put("jetzig", jetzig.module("jetzig")); try b.modules.put("jetzig", jetzig.module("jetzig"));
const zmpl_dep = b.dependency(
"zmpl",
.{
.target = target,
.optimize = optimize,
.zmpl_templates_path = @as([]const u8, "src/app/views/"),
.zmpl_manifest_path = @as([]const u8, "src/app/views/zmpl.manifest.zig"),
},
);
exe.addModule("zmpl", zmpl_dep.module("zmpl"));
try b.modules.put("zmpl", zmpl_dep.module("zmpl"));
const run_cmd = b.addRunArtifact(exe); const run_cmd = b.addRunArtifact(exe);
run_cmd.step.dependOn(b.getInstallStep()); run_cmd.step.dependOn(b.getInstallStep());

View File

@ -4,7 +4,10 @@
.dependencies = .{ .dependencies = .{
.jetzig = .{ .jetzig = .{
.url = "https://github.com/jetzig-framework/jetzig/archive/refs/tags/dev.tar.gz", .url = "https://github.com/jetzig-framework/jetzig/archive/refs/tags/dev.tar.gz",
.hash = "122097efa94bcbc548aa170ea1c58afe6f21101032f8436a9324ea0435adbaa227ef", },
.zmpl = .{
.url = "https://github.com/jetzig-framework/zmpl/archive/refs/tags/0.0.1.tar.gz",
.hash = "12204256376f262a58935d66a2a0b41ac0447299b7e63a4c6ff160ddcef6572cd3c7",
}, },
}, },

BIN
src/init/public/jetzig.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

View File

@ -0,0 +1,102 @@
[{"quote": "Life isnt about getting and having, its about giving and being.", "author": "Kevin Kruse"},
{"quote": "Whatever the mind of man can conceive and believe, it can achieve.", "author": "Napoleon Hill"},
{"quote": "Strive not to be a success, but rather to be of value.", "author": "Albert Einstein"},
{"quote": "Two roads diverged in a wood, and I—I took the one less traveled by, And that has made all the difference.", "author": "Robert Frost"},
{"quote": "I attribute my success to this: I never gave or took any excuse.", "author": "Florence Nightingale"},
{"quote": "You miss 100% of the shots you dont take.", "author": "Wayne Gretzky"},
{"quote": "Ive missed more than 9000 shots in my career. Ive lost almost 300 games. 26 times Ive been trusted to take the game winning shot and missed. Ive failed over and over and over again in my life. And that is why I succeed.", "author": "Michael Jordan"},
{"quote": "The most difficult thing is the decision to act, the rest is merely tenacity.", "author": "Amelia Earhart"},
{"quote": "Every strike brings me closer to the next home run.", "author": "Babe Ruth"},
{"quote": "Definiteness of purpose is the starting point of all achievement.", "author": "W. Clement Stone"},
{"quote": "We must balance conspicuous consumption with conscious capitalism.", "author": "Kevin Kruse"},
{"quote": "Life is what happens to you while youre busy making other plans.", "author": "John Lennon"},
{"quote": "We become what we think about.", "author": "Earl Nightingale"},
{"quote": "14.Twenty years from now you will be more disappointed by the things that you didnt do than by the ones you did do, so throw off the bowlines, sail away from safe harbor, catch the trade winds in your sails. Explore, Dream, Discover.", "author": "Mark Twain"},
{"quote": "15.Life is 10% what happens to me and 90% of how I react to it.", "author": "Charles Swindoll"},
{"quote": "The most common way people give up their power is by thinking they dont have any.", "author": "Alice Walker"},
{"quote": "The mind is everything. What you think you become.", "author": "Buddha"},
{"quote": "The best time to plant a tree was 20 years ago. The second best time is now.", "author": "Chinese Proverb"},
{"quote": "An unexamined life is not worth living.", "author": "Socrates"},
{"quote": "Eighty percent of success is showing up.", "author": "Woody Allen"},
{"quote": "Your time is limited, so dont waste it living someone elses life.", "author": "Steve Jobs"},
{"quote": "Winning isnt everything, but wanting to win is.", "author": "Vince Lombardi"},
{"quote": "I am not a product of my circumstances. I am a product of my decisions.", "author": "Stephen Covey"},
{"quote": "Every child is an artist. The problem is how to remain an artist once he grows up.", "author": "Pablo Picasso"},
{"quote": "You can never cross the ocean until you have the courage to lose sight of the shore.", "author": "Christopher Columbus"},
{"quote": "Ive learned that people will forget what you said, people will forget what you did, but people will never forget how you made them feel.", "author": "Maya Angelou"},
{"quote": "Either you run the day, or the day runs you.", "author": "Jim Rohn"},
{"quote": "Whether you think you can or you think you cant, youre right.", "author": "Henry Ford"},
{"quote": "The two most important days in your life are the day you are born and the day you find out why.", "author": "Mark Twain"},
{"quote": "Whatever you can do, or dream you can, begin it. Boldness has genius, power and magic in it.", "author": "Johann Wolfgang von Goethe"},
{"quote": "The best revenge is massive success.", "author": "Frank Sinatra"},
{"quote": "People often say that motivation doesnt last. Well, neither does bathing. Thats why we recommend it daily.", "author": "Zig Ziglar"},
{"quote": "Life shrinks or expands in proportion to ones courage.", "author": "Anais Nin"},
{"quote": "If you hear a voice within you say “you cannot paint,” then by all means paint and that voice will be silenced.", "author": "Vincent Van Gogh"},
{"quote": "There is only one way to avoid criticism: do nothing, say nothing, and be nothing.", "author": "Aristotle"},
{"quote": "Ask and it will be given to you; search, and you will find; knock and the door will be opened for you.", "author": "Jesus"},
{"quote": "The only person you are destined to become is the person you decide to be.", "author": "Ralph Waldo Emerson"},
{"quote": "Go confidently in the direction of your dreams. Live the life you have imagined.", "author": "Henry David Thoreau"},
{"quote": "When I stand before God at the end of my life, I would hope that I would not have a single bit of talent left and could say, I used everything you gave me.", "author": "Erma Bombeck"},
{"quote": "Few things can help an individual more than to place responsibility on him, and to let him know that you trust him.", "author": "Booker T. Washington"},
{"quote": "Certain things catch your eye, but pursue only those that capture the heart.", "author": " Ancient Indian Proverb"},
{"quote": "Believe you can and youre halfway there.", "author": "Theodore Roosevelt"},
{"quote": "Everything youve ever wanted is on the other side of fear.", "author": "George Addair"},
{"quote": "We can easily forgive a child who is afraid of the dark; the real tragedy of life is when men are afraid of the light.", "author": "Plato"},
{"quote": "Teach thy tongue to say, “I do not know,” and thous shalt progress.", "author": "Maimonides"},
{"quote": "Start where you are. Use what you have. Do what you can.", "author": "Arthur Ashe"},
{"quote": "When I was 5 years old, my mother always told me that happiness was the key to life. When I went to school, they asked me what I wanted to be when I grew up. I wrote down happy. They told me I didnt understand the assignment, and I told them they didnt understand life.", "author": "John Lennon"},
{"quote": "Fall seven times and stand up eight.", "author": "Japanese Proverb"},
{"quote": "When one door of happiness closes, another opens, but often we look so long at the closed door that we do not see the one that has been opened for us.", "author": "Helen Keller"},
{"quote": "Everything has beauty, but not everyone can see.", "author": "Confucius"},
{"quote": "How wonderful it is that nobody need wait a single moment before starting to improve the world.", "author": "Anne Frank"},
{"quote": "When I let go of what I am, I become what I might be.", "author": "Lao Tzu"},
{"quote": "Life is not measured by the number of breaths we take, but by the moments that take our breath away.", "author": "Maya Angelou"},
{"quote": "Happiness is not something readymade. It comes from your own actions.", "author": "Dalai Lama"},
{"quote": "If youre offered a seat on a rocket ship, dont ask what seat! Just get on.", "author": "Sheryl Sandberg"},
{"quote": "First, have a definite, clear practical ideal; a goal, an objective. Second, have the necessary means to achieve your ends; wisdom, money, materials, and methods. Third, adjust all your means to that end.", "author": "Aristotle"},
{"quote": "If the wind will not serve, take to the oars.", "author": "Latin Proverb"},
{"quote": "You cant fall if you dont climb. But theres no joy in living your whole life on the ground.", "author": "Unknown"},
{"quote": "We must believe that we are gifted for something, and that this thing, at whatever cost, must be attained.", "author": "Marie Curie"},
{"quote": "Too many of us are not living our dreams because we are living our fears.", "author": "Les Brown"},
{"quote": "Challenges are what make life interesting and overcoming them is what makes life meaningful.", "author": "Joshua J. Marine"},
{"quote": "If you want to lift yourself up, lift up someone else.", "author": "Booker T. Washington"},
{"quote": "I have been impressed with the urgency of doing. Knowing is not enough; we must apply. Being willing is not enough; we must do.", "author": "Leonardo da Vinci"},
{"quote": "Limitations live only in our minds. But if we use our imaginations, our possibilities become limitless.", "author": "Jamie Paolinetti"},
{"quote": "You take your life in your own hands, and what happens? A terrible thing, no one to blame.", "author": "Erica Jong"},
{"quote": "Whats money? A man is a success if he gets up in the morning and goes to bed at night and in between does what he wants to do.", "author": "Bob Dylan"},
{"quote": "I didnt fail the test. I just found 100 ways to do it wrong.", "author": "Benjamin Franklin"},
{"quote": "In order to succeed, your desire for success should be greater than your fear of failure.", "author": "Bill Cosby"},
{"quote": "A person who never made a mistake never tried anything new.", "author": " Albert Einstein"},
{"quote": "The person who says it cannot be done should not interrupt the person who is doing it.", "author": "Chinese Proverb"},
{"quote": "There are no traffic jams along the extra mile.", "author": "Roger Staubach"},
{"quote": "It is never too late to be what you might have been.", "author": "George Eliot"},
{"quote": "You become what you believe.", "author": "Oprah Winfrey"},
{"quote": "I would rather die of passion than of boredom.", "author": "Vincent van Gogh"},
{"quote": "A truly rich man is one whose children run into his arms when his hands are empty.", "author": "Unknown"},
{"quote": "It is not what you do for your children, but what you have taught them to do for themselves, that will make them successful human beings.", "author": "Ann Landers"},
{"quote": "If you want your children to turn out well, spend twice as much time with them, and half as much money.", "author": "Abigail Van Buren"},
{"quote": "Build your own dreams, or someone else will hire you to build theirs.", "author": "Farrah Gray"},
{"quote": "The battles that count arent the ones for gold medals. The struggles within yourselfthe invisible battles inside all of usthats where its at.", "author": "Jesse Owens"},
{"quote": "Education costs money. But then so does ignorance.", "author": "Sir Claus Moser"},
{"quote": "I have learned over the years that when ones mind is made up, this diminishes fear.", "author": "Rosa Parks"},
{"quote": "It does not matter how slowly you go as long as you do not stop.", "author": "Confucius"},
{"quote": "If you look at what you have in life, youll always have more. If you look at what you dont have in life, youll never have enough.", "author": "Oprah Winfrey"},
{"quote": "Remember that not getting what you want is sometimes a wonderful stroke of luck.", "author": "Dalai Lama"},
{"quote": "You cant use up creativity. The more you use, the more you have.", "author": "Maya Angelou"},
{"quote": "Dream big and dare to fail.", "author": "Norman Vaughan"},
{"quote": "Our lives begin to end the day we become silent about things that matter.", "author": "Martin Luther King Jr."},
{"quote": "Do what you can, where you are, with what you have.", "author": "Teddy Roosevelt"},
{"quote": "If you do what youve always done, youll get what youve always gotten.", "author": "Tony Robbins"},
{"quote": "Dreaming, after all, is a form of planning.", "author": "Gloria Steinem"},
{"quote": "Its your place in the world; its your life. Go on and do all you can with it, and make it the life you want to live.", "author": "Mae Jemison"},
{"quote": "You may be disappointed if you fail, but you are doomed if you dont try.", "author": "Beverly Sills"},
{"quote": "Remember no one can make you feel inferior without your consent.", "author": "Eleanor Roosevelt"},
{"quote": "Life is what we make it, always has been, always will be.", "author": "Grandma Moses"},
{"quote": "The question isnt who is going to let me; its who is going to stop me.", "author": "Ayn Rand"},
{"quote": "When everything seems to be going against you, remember that the airplane takes off against the wind, not with it.", "author": "Henry Ford"},
{"quote": "Its not the years in your life that count. Its the life in your years.", "author": "Abraham Lincoln"},
{"quote": "Change your thoughts and you change your world.", "author": "Norman Vincent Peale"},
{"quote": "Either write something worth reading or do something worth writing.", "author": "Benjamin Franklin"},
{"quote": "Nothing is impossible, the word itself says, “Im possible!”", "author": "Audrey Hepburn"},
{"quote": "The only way to do great work is to love what you do.", "author": "Steve Jobs"},
{"quote": "If you can dream it, you can achieve it.", "author": "Zig Ziglar"}]

View File

@ -0,0 +1,27 @@
<html>
<head>
<script src="https://unpkg.com/htmx.org@1.9.10"></script>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="https://cdn.tailwindcss.com"></script>
</head>
<body>
<div class="text-center pt-10 m-auto">
<div><img class="p-3 mx-auto" src="/jetzig.png" /></div>
<div>
<h1 class="text-3xl text-center p-3 pb-6 font-bold">Welcome to Jetzig!</h1>
</div>
<button hx-get="/quotes/random" hx-trigger="click" hx-target="#quote" class="bg-[#39b54a] text-white font-bold py-2 px-4 rounded">Click Me</button>
<div id="quote" class="p-7 mx-auto w-1/2">
<div hx-get="/quotes/init" hx-trigger="load"></div>
</div>
<div>Take a look at the <span class="font-mono">src/app/</span> directory to see how this application works.</div>
<div>Visit <a class="font-bold text-[#39b54a]" href="https://jetzig.dev/">jetzig.dev</a> to get started.</div>
</div>
</body>
</html>

View File

@ -0,0 +1,34 @@
const std = @import("std");
const jetzig = @import("jetzig");
const Request = jetzig.http.Request;
const Data = jetzig.data.Data;
const View = jetzig.views.View;
pub fn get(id: []const u8, request: *Request, data: *Data) anyerror!View {
var body = try data.object();
const random_quote = try randomQuote(request.allocator);
if (std.mem.eql(u8, id, "random")) {
try body.put("quote", data.string(random_quote.quote));
try body.put("author", data.string(random_quote.author));
} else {
try body.put("quote", data.string("If you can dream it, you can achieve it."));
try body.put("author", data.string("Zig Ziglar"));
}
return request.render(.ok);
}
const Quote = struct {
quote: []const u8,
author: []const u8,
};
// Quotes taken from: https://gist.github.com/natebass/b0a548425a73bdf8ea5c618149fe1fce
fn randomQuote(allocator: std.mem.Allocator) !Quote {
const json = try std.fs.cwd().readFileAlloc(allocator, "src/app/config/quotes.json", 12684);
const quotes = try std.json.parseFromSlice([]Quote, allocator, json, .{});
return quotes.value[std.crypto.random.intRangeLessThan(usize, 0, quotes.value.len)];
}

View File

@ -0,0 +1,2 @@
<div>"{.quote}"</div>
<div><b>--{.author}</b></div>

View File

@ -10,6 +10,11 @@ pub const views = @import("jetzig/views.zig");
pub const colors = @import("jetzig/colors.zig"); pub const colors = @import("jetzig/colors.zig");
pub const App = @import("jetzig/App.zig"); pub const App = @import("jetzig/App.zig");
pub const config = struct {
pub const max_bytes_request_body: usize = std.math.pow(usize, 2, 16);
pub const max_bytes_static_content: usize = std.math.pow(usize, 2, 16);
};
pub fn init(allocator: std.mem.Allocator) !App { pub fn init(allocator: std.mem.Allocator) !App {
const args = try std.process.argsAlloc(allocator); const args = try std.process.argsAlloc(allocator);
defer std.process.argsFree(allocator, args); defer std.process.argsFree(allocator, args);

View File

@ -7,15 +7,18 @@ const Self = @This();
allocator: std.mem.Allocator, allocator: std.mem.Allocator,
content: []const u8, content: []const u8,
status_code: http.status_codes.StatusCode, status_code: http.status_codes.StatusCode,
content_type: []const u8,
pub fn init( pub fn init(
allocator: std.mem.Allocator, allocator: std.mem.Allocator,
content: []const u8, content: []const u8,
status_code: http.status_codes.StatusCode, status_code: http.status_codes.StatusCode,
content_type: []const u8,
) Self { ) Self {
return .{ return .{
.status_code = status_code, .status_code = status_code,
.content = content, .content = content,
.content_type = content_type,
.allocator = allocator, .allocator = allocator,
}; };
} }
@ -23,12 +26,14 @@ pub fn init(
pub fn deinit(self: *const Self) void { pub fn deinit(self: *const Self) void {
_ = self; _ = self;
// self.allocator.free(self.content); // self.allocator.free(self.content);
// self.allocator.free(self.content_type);
} }
pub fn dupe(self: *const Self) !Self { pub fn dupe(self: *const Self) !Self {
return .{ return .{
.allocator = self.allocator, .allocator = self.allocator,
.status_code = self.status_code, .status_code = self.status_code,
.content_type = try self.allocator.dupe(u8, self.content_type),
.content = try self.allocator.dupe(u8, self.content), .content = try self.allocator.dupe(u8, self.content),
}; };
} }

View File

@ -61,7 +61,7 @@ pub fn listen(self: *Self) !void {
fn processRequests(self: *Self) !void { fn processRequests(self: *Self) !void {
while (true) { while (true) {
var response = try self.server.accept(.{ .allocator = self.allocator }); var response = try self.server.accept(.{ .allocator = self.allocator });
defer response.deinit(); errdefer response.deinit();
try response.headers.append("Connection", "close"); try response.headers.append("Connection", "close");
@ -74,6 +74,8 @@ fn processRequests(self: *Self) !void {
} }
}; };
} }
response.deinit();
} }
} }
@ -82,7 +84,7 @@ fn processNextRequest(self: *Self, response: *std.http.Server.Response) !void {
self.start_time = std.time.nanoTimestamp(); self.start_time = std.time.nanoTimestamp();
const body = try response.reader().readAllAlloc(self.allocator, 8192); // FIXME: Configurable max body size const body = try response.reader().readAllAlloc(self.allocator, jetzig.config.max_bytes_request_body);
defer self.allocator.free(body); defer self.allocator.free(body);
var arena = std.heap.ArenaAllocator.init(self.allocator); var arena = std.heap.ArenaAllocator.init(self.allocator);
@ -99,6 +101,7 @@ fn processNextRequest(self: *Self, response: *std.http.Server.Response) !void {
while (try cookie_it.next()) |header| { while (try cookie_it.next()) |header| {
try response.headers.append("Set-Cookie", header); try response.headers.append("Set-Cookie", header);
} }
try response.headers.append("Content-Type", result.value.content_type);
response.status = switch (result.value.status_code) { response.status = switch (result.value.status_code) {
inline else => |status_code| @field(std.http.Status, @tagName(status_code)), inline else => |status_code| @field(std.http.Status, @tagName(status_code)),
}; };
@ -125,15 +128,39 @@ fn pageContent(self: *Self, request: *jetzig.http.Request) !jetzig.caches.Result
} }
fn renderResponse(self: *Self, request: *jetzig.http.Request) !jetzig.http.Response { fn renderResponse(self: *Self, request: *jetzig.http.Request) !jetzig.http.Response {
const view = try self.matchView(request); const static = self.matchStaticResource(request) catch |err| {
if (isUnhandledError(err)) return err;
const rendered = try self.internalServerError(request, err);
return .{
.allocator = self.allocator,
.status_code = .internal_server_error,
.content = rendered.content,
.content_type = "text/html",
};
};
if (static) |resource| return try self.renderStatic(request, resource);
const route = try self.matchRoute(request);
switch (request.requestFormat()) { switch (request.requestFormat()) {
.HTML => return self.renderHTML(request, view), .HTML => return self.renderHTML(request, route),
.JSON => return self.renderJSON(request, view), .JSON => return self.renderJSON(request, route),
.UNKNOWN => return self.renderHTML(request, view), .UNKNOWN => return self.renderHTML(request, route),
} }
} }
fn renderStatic(self: *Self, request: *jetzig.http.Request, resource: StaticResource) !jetzig.http.Response {
_ = request;
// TODO: Select an appropriate header from MIME type and add to request.response.headers
return .{
.allocator = self.allocator,
.status_code = .ok,
.content = resource.content,
.content_type = "application/octet-stream",
};
}
fn renderHTML( fn renderHTML(
self: *Self, self: *Self,
request: *jetzig.http.Request, request: *jetzig.http.Request,
@ -152,6 +179,7 @@ fn renderHTML(
.allocator = self.allocator, .allocator = self.allocator,
.content = rendered.content, .content = rendered.content,
.status_code = rendered.view.status_code, .status_code = rendered.view.status_code,
.content_type = "text/html",
}; };
} }
} }
@ -160,12 +188,14 @@ fn renderHTML(
.allocator = self.allocator, .allocator = self.allocator,
.content = "", .content = "",
.status_code = .not_found, .status_code = .not_found,
.content_type = "text/html",
}; };
} else { } else {
return .{ return .{
.allocator = self.allocator, .allocator = self.allocator,
.content = "", .content = "",
.status_code = .not_found, .status_code = .not_found,
.content_type = "text/html",
}; };
} }
} }
@ -180,20 +210,24 @@ fn renderJSON(
var data = rendered.view.data; var data = rendered.view.data;
if (data.value) |_| {} else _ = try data.object(); if (data.value) |_| {} else _ = try data.object();
try request.headers.append("Content-Type", "application/json");
return .{ return .{
.allocator = self.allocator, .allocator = self.allocator,
.content = try data.toJson(), .content = try data.toJson(),
.status_code = rendered.view.status_code, .status_code = rendered.view.status_code,
.content_type = "application/json",
}; };
} else return .{ } else return .{
.allocator = self.allocator, .allocator = self.allocator,
.content = "", .content = "",
.status_code = .not_found, .status_code = .not_found,
.content_type = "application/json",
}; };
} }
const RenderedView = struct { view: jetzig.views.View, content: []const u8 }; const RenderedView = struct { view: jetzig.views.View, content: []const u8 };
fn renderView( fn renderView(
self: *Self, self: *Self,
matched_route: jetzig.views.Route, matched_route: jetzig.views.Route,
@ -202,16 +236,21 @@ fn renderView(
) !RenderedView { ) !RenderedView {
const view = matched_route.render(matched_route, request) catch |err| { const view = matched_route.render(matched_route, request) catch |err| {
self.logger.debug("Encountered error: {s}", .{@errorName(err)}); self.logger.debug("Encountered error: {s}", .{@errorName(err)});
switch (err) { if (isUnhandledError(err)) return err;
error.OutOfMemory => return err, return try self.internalServerError(request, err);
else => return try self.internalServerError(request, err),
}
}; };
const content = if (template) |capture| try capture.render(view.data) else ""; const content = if (template) |capture| try capture.render(view.data) else "";
return .{ .view = view, .content = content }; return .{ .view = view, .content = content };
} }
fn isUnhandledError(err: anyerror) bool {
return switch (err) {
error.OutOfMemory => true,
else => false,
};
}
fn internalServerError(self: *Self, request: *jetzig.http.Request, err: anyerror) !RenderedView { fn internalServerError(self: *Self, request: *jetzig.http.Request, err: anyerror) !RenderedView {
_ = self; _ = self;
request.response_data.reset(); request.response_data.reset();
@ -248,7 +287,7 @@ fn duration(self: *Self) i64 {
return @intCast(std.time.nanoTimestamp() - self.start_time); return @intCast(std.time.nanoTimestamp() - self.start_time);
} }
fn matchView(self: *Self, request: *jetzig.http.Request) !?jetzig.views.Route { fn matchRoute(self: *Self, request: *jetzig.http.Request) !?jetzig.views.Route {
for (self.routes) |route| { for (self.routes) |route| {
if (route.action == .index and try request.match(route)) return route; if (route.action == .index and try request.match(route)) return route;
} }
@ -259,3 +298,34 @@ fn matchView(self: *Self, request: *jetzig.http.Request) !?jetzig.views.Route {
return null; return null;
} }
const StaticResource = struct { content: []const u8, mime_type: []const u8 = undefined };
fn matchStaticResource(self: *Self, request: *jetzig.http.Request) !?StaticResource {
_ = self;
if (request.path.len < 2) return null;
if (request.method != .GET) return null;
var iterable_dir = std.fs.cwd().openIterableDir("public", .{}) catch |err| {
switch (err) {
error.FileNotFound => return null,
else => return err,
}
};
var walker = try iterable_dir.walk(request.allocator);
while (try walker.next()) |file| {
if (file.kind != .file) continue;
if (std.mem.eql(u8, file.path, request.path[1..])) {
return .{
.content = try iterable_dir.dir.readFileAlloc(
request.allocator,
file.path,
jetzig.config.max_bytes_static_content,
),
};
}
}
return null;
}