All the sources so far

Here is source\app.d:

import vibe.vibe;
import empcontrol;

void main()
{
  auto settings = new HTTPServerSettings;
  settings.port = 8080;
  settings.bindAddresses = ["::1", "127.0.0.1"];
  settings.sessionStore = new MemorySessionStore;
  auto router = new URLRouter;
  router.get("*", serveStaticFiles("public/"));
  router.registerWebInterface(new EmployeeController);
  auto listener = listenHTTP(settings, router);
  scope (exit) listener.stopListening();
 
  runApplication();
}

Here is source\empcontrol.d:

module empcontrol;
import vibe.vibe;
import empmodel;

struct User 
{
  bool loggedIn;
  string email;
}

class EmployeeController
{
  private EmployeeModel empModel;
  private string realm = "The Lorem Ipsum Company";
  private SessionVar!(User, "user") m_user;
 
  this()
  {
    empModel = new EmployeeModel;
  }
  
  void index(string _error = null)
  {
    string error = _error;
    m_user = User.init;
    terminateSession;
    render!("index.dt", error);
  }
  
  @auth
  void getAddEmployee(string _authUser, string _error = null)
  {
    string error = _error;
    render!("empadd.dt", departments, paygrades, provinces, error);
  }
  
  @errorDisplay!getAddEmployee
  void postAddEmployee(Employee e)
  {
    import std.file;
    import std.path;
    import std.algorithm;
    import vibe.http.auth.digest_auth;
    auto pic = "picture" in request.files;
    if(pic !is null)
    {
      string photopath = "none yet";
      string ext = extension(pic.filename.name);
      string[] exts = [".jpg", ".jpeg", ".png", ".gif"];
      if(canFind(exts, ext))
      {
        photopath = "uploads/photos/" ~ e.fname ~ "_" ~ e.lname ~ ext;
        string dir = "./public/uploads/photos/";
        mkdirRecurse(dir);
        string fullpath = dir ~ e.fname ~ "_" ~ e.lname ~ ext;
        try moveFile(pic.tempPath, NativePath(fullpath));
        catch (Exception ex) copyFile(pic.tempPath, NativePath(fullpath), true);
      }
      e.photo = photopath;
    }
    if(e.phone.length == 0) e.phone = "(123) 456 7890";
    if(e.paygd.length == 0) e.paygd = "none yet";
    if(e.postcode.length == 0) e.postcode = "A1A 1A1";
    e.pword = createDigestPassword(realm, e.email, e.pword);
    empModel.addEmployee(e);
    redirect("all_employees");
  }
  
  @auth
  void getAllEmployees(string _authUser, string _error = null)
  {
    string error = _error;
    Employee[] emps = empModel.getEmployees;
    render!("emplistall.dt", emps, error);
  }
  
  @auth
  void getEditEmployee(string _authUser, int id, string _error = null)
  {
    string error = _error;
    Employee e = empModel.getEmployee(id);
    render!("empedit.dt", e, departments, paygrades, provinces, error);
  }
  
  @errorDisplay!getEditEmployee
  void postEditEmployee(Employee e)
  {
    import std.file;
    import std.path;
    import std.algorithm;
    import vibe.http.auth.digest_auth;
    string photopath = e.photo;
    auto pic = "picture" in request.files;
    if(pic !is null)
    {
      string ext = extension(pic.filename.name);
      string[] exts = [".jpg", ".jpeg", ".png", ".gif"];
      if(canFind(exts, ext))
      {
        photopath = "uploads/photos/" ~ e.fname ~ "_" ~ e.lname ~ ext;
        string dir = "./public/uploads/photos/";
        mkdirRecurse(dir);
        string fullpath = dir ~ e.fname ~ "_" ~ e.lname ~ ext;
        try moveFile(pic.tempPath, NativePath(fullpath));
        catch (Exception ex) copyFile(pic.tempPath, NativePath(fullpath), true);
      }
    }
    e.photo = photopath;
    if(e.phone.length == 0) e.phone = "(123) 456 7890";
    if(e.paygd.length == 0) e.paygd = "none yet";
    if(e.postcode.length == 0) e.postcode = "A1A 1A1";
    e.pword = createDigestPassword(realm, e.email, e.pword);
    empModel.editEmployee(e);
    redirect("all_employees");
  }
  
  @auth
  void getDeleteEmployee(string _authUser, int id, string _error = null)
  {
    string error = _error;
    Employee e = empModel.getEmployee(id);
    render!("empdelete.dt", e, error);
  }
  
  @errorDisplay!getDeleteEmployee
  void postDeleteEmployee(int id)
  {
    empModel.deleteEmployee(id);
    redirect("all_employees");
  }
  
  @auth
  @errorDisplay!getAllEmployees
  void postFindEmployee(string _authUser, string fname, string lname)
  {
    import std.uni; //so we can use the toUpper() function
    string first = toUpper(fname);
    string last = toUpper(lname);
    Employee e = empModel.findEmployee(first, last);
    enforce(e != Employee.init, fname ~ " " ~ lname ~ " not found.");
    render!("employee.dt", e);
  }
  
  @errorDisplay!index
  void postLogin(string email, string password)
  {
    import vibe.http.auth.digest_auth;
   
    auto scrambled = createDigestPassword(realm, email, password);
    bool isAdmin = empModel.isAdmin(email, scrambled);
    enforce(isAdmin, "Email and password combination not found.");
    User user = m_user;
    user.loggedIn = true;
    user.email = email;
    m_user = user;
    redirect("all_employees");
  }
  
  private enum auth = before!ensureAuth("_authUser");
  
  
  private string ensureAuth(HTTPServerRequest req, HTTPServerResponse res)
  {
    if(!m_user.loggedIn) redirect("/");
    return m_user.email;
  }
  mixin PrivateAccessProxy;
}

And here is source\empmodel.d:

module empmodel;
import mysql;
import std.conv;
import std.array;

struct Employee
{
  int id; //row id or record id
  string empid; //employee number
  string deprt; //department
  string paygd; //salary grade
  string email; //email address
  string pword; //password
  string fname; //first name
  string lname; //last name
  string phone; //phone number
  string photo; //ID photo
  string street; //street address
  string city; //city name
  string province; //province name
  string postcode; //postal code
}

struct Admin
{
  string email; //email address
  string pword; //passsword
}

string[] departments =
[
  "Management and Admin",
  "Accounting and Finance",
  "Production",
  "Maintenance",
  "Shipping and Receiving",
  "Purchasing and Supplies",
  "IT Services",
  "Human Resources",
  "Marketing"
];

string[][] provinces =
[
  ["AB", "Alberta"],
  ["BC", "British Columbia"],
  ["MB", "Manitoba"],
  ["NB", "New Brunswick"],
  ["NL", "Newfoundland and Labrador"],
  ["NS", "Nova Scotia"],
  ["NT", "Northwest Territories"],
  ["NU", "Nunavut"],
  ["ON", "Ontario"],
  ["PE", "Prince Edward Island"],
  ["QC", "Quebec"],
  ["SK", "Saskatchewan"],
  ["YT", "Yukon Territory"]
];

string[] paygrades =
[
  "A100", "A200", "A300", "A400",
  "B100", "B200", "B300", "B400",
  "C100", "C200", "C300", "C400",
  "D100", "D200", "D300", "D400",
  "E100", "E200", "E300", "E400",
  "F100", "F200", "F300", "F400"
];

class EmployeeModel
{
  Connection conn;
  
  this()
  {
    string url = "host=localhost;port=3306;user=owner;pwd=qwerty;db=empdb";
    conn = new Connection(url);
    scope(exit) conn.close;
  }
  
  ulong addEmployee(Employee e)
  {
    string sql =
      "insert into employees
      (
        empid,
        deprt, paygd, email, pword,
        fname, lname, phone, photo,
        street, city, province, postcode
      )
      values(?,?,?,?,?,?,?,?,?,?,?,?,?)";
    Prepared pstmt = conn.prepare(sql);
    pstmt.setArgs
    (
      to!string(e.empid),
      to!string(e.deprt),
      to!string(e.paygd),
      to!string(e.email),
      to!string(e.pword),
      to!string(e.fname),
      to!string(e.lname),
      to!string(e.phone),
      to!string(e.photo),
      to!string(e.street),
      to!string(e.city),
      to!string(e.province),
      to!string(e.postcode)
    );
    return conn.exec(pstmt);
  }
  
  Employee[] getEmployees()
  {
    Employee[] emps;
    string sql = "select * from employees";
    Row[] rows = conn.query(sql).array;
    if(rows.length == 0) return emps;
    return prepareEmployees(rows);
  }
  
  Employee[] prepareEmployees(Row[] rows)
  {
    Employee[] emps;
    foreach(row; rows)
    {
      Employee e = prepareEmployee(row);
      emps ~= e;
    }
    return emps;
  }
  
  Employee prepareEmployee(Row row)
  {
    Employee e;
    e.id = to!int(to!string(row[0]));
    e.empid = to!string(row[1]);
    e.deprt = to!string(row[2]);
    e.paygd = to!string(row[3]);
    e.email = to!string(row[4]);
    e.pword = to!string(row[5]);
    e.fname = to!string(row[6]);
    e.lname = to!string(row[7]);
    e.phone = to!string(row[8]);
    e.photo = to!string(row[9]);
    e.street = to!string(row[10]);
    e.city = to!string(row[11]);
    e.province = to!string(row[12]);
    e.postcode = to!string(row[13]);
    return e;
  }
  
  Employee getEmployee(int id)
  {
    string sql = "select * from employees where id=?";
    Prepared pstmt = conn.prepare(sql);
    pstmt.setArgs(id);
    Employee e;
    Row[] rows = conn.query(pstmt).array;
    if(rows.length == 0) return e;
    return prepareEmployee(rows[0]);
  }
  
  ulong editEmployee(Employee e)
  {
    string sql = "update employees set empid=?,
      deprt=?, paygd=?, email=?, pword=?,
      fname=?, lname=?, phone=?, photo=?,
      street=?, city=?, province=?, postcode=?
      where id=?";
    Prepared pstmt = conn.prepare(sql);
    pstmt.setArgs
    (
      to!string(e.empid),
      to!string(e.deprt),
      to!string(e.paygd),
      to!string(e.email),
      to!string(e.pword),
      to!string(e.fname),
      to!string(e.lname),
      to!string(e.phone),
      to!string(e.photo),
      to!string(e.street),
      to!string(e.city),
      to!string(e.province),
      to!string(e.postcode),
      to!int(to!string(e.id))
    );
    return conn.exec(pstmt);
  }
  
  void deleteEmployee(int id)
  {
    string sql = "delete from employees where id=?";
    Prepared pstmt = conn.prepare(sql);
    pstmt.setArgs(id);
    conn.exec(pstmt);
  }
  
  Employee findEmployee(string first, string last)
  {
    Employee e;
    string sql = "select * from employees where upper(fname)=? and upper(lname)=?";
    Prepared pstmt = conn.prepare(sql);
    pstmt.setArgs(first, last);
    Row[] rows = conn.query(pstmt).array;
    if(rows.length == 0) return e;
    return prepareEmployee(rows[0]);
  }
  
  bool isAdmin(string email, string password)
  {
    string sql = "select * from admins where email=? and pword=?";
    Prepared pstmt = conn.prepare(sql);
    pstmt.setArgs(email, password);
    Row[] rows = conn.query(pstmt).array;
    if(rows.length == 0) return false;
    return true;
  }
}

Here is views\cssformgrid.dt:

:css 
  .form-grid-wrapper
  {
    width: 700px;
    height: auto;
    margin: 20px auto;
    padding: 1px 20px 20px 0;
    border-radius: 20px;
    background-color: #eef;
  }
  .form-grid
  {
    display: grid;
    grid-template-columns: 1fr 3fr;
    gap: 5px;
  }
  .center-align
  {
    text-align: center;
  }
  .form-grid-label
  {
    width: 100%;
    font-size: 16px;
    text-align: right;
    padding: 2px;
  }
  .form-grid-input
  {
    width: 100%;
    font-size: 14px;
    padding: 0;
  }
  .form-grid-field
  {
    width: 100%;
    font-size: 16px;
    border-bottom: 1px solid black;
    padding: 2px;
  }
  .form-grid-button
  {
    width: 100%;
    font-size: 14px;
    height: 30px;
    margin-top: 10px;
  }

Here is views\csstable.dt:

:css
  .table-wrapper
  {
    margin: 20px auto;
    border-radius: 20px;
  }
  table
  {
    margin: 0 auto;
    padding: 20px 0;
    border-collapse: collapse;
    background-color: #eef;
  }
  table td, table th
  {
    border: 1px solid black;
    margin: 0;
    padding: 0 5px;
  }
  .no-border
  {
    border: 0;
  }

Here is views\empadd.dt:

extends layout
block maincontent
  include cssformgrid.dt
  -if(error)
    div.error-div
      span.error-message #{error}
  div.form-grid-wrapper
    h2.center-align New employee details
    form.form-grid(method="post", action="add_employee", enctype="multipart/form-data")
      label.form-grid-label Employee number
      input.form-grid-input(type="empid", name="e_empid", placeholder="employee number", required)
      label.form-grid-label Department
      select#deprt.form-grid-input(name="e_deprt")
        -foreach(dep; departments)
          option(value="#{dep}") #{dep}
      label.form-grid-label Salary grade
      select#deprt.form-grid-input(name="e_paygd")
        -foreach(pay; paygrades)
          option(value="#{pay}") #{pay}
      label.form-grid-label Email address
      input.form-grid-input(type="email", name="e_email", placeholder="email@company.com", required)
      label.form-grid-label Password
      input.form-grid-input(type="password", name="e_pword", placeholder="password", required)
      label.form-grid-label First name
      input.form-grid-input(type="text", name="e_fname", placeholder="First name", required)
      label.form-grid-label Last name
      input.form-grid-input(type="text", name="e_lname", placeholder="Last name", required)
      label.form-grid-label Phone
      input.form-grid-input(type="text", name="e_phone", placeholder="Phone number")
      label.form-grid-label Street address (no city)
      input.form-grid-input(type="text", name="e_street", placeholder="Street address", required)
      label.form-grid-label City
      input.form-grid-input(type="text", name="e_city", placeholder="City", required)
      label.form-grid-label Province
      select#province.form-grid-input(name="e_province")
        -foreach(prov; provinces)
          option(value="#{prov[0]}") #{prov[1]}
      label.form-grid-label Postal code
      input.form-grid-input(type="text", name="e_postcode", placeholder="A1A 1A1")
      label.form-grid-label ID Picture
      input.form-grid-input(type="file", name="picture")
      input(type="hidden", name="e_photo")
      input(type="hidden", name="e_id", value="1")
      div
      div
        input.form-grid-button(type="reset", value="Clear the form")
        input.form-grid-button(type="submit", value="Submit")

Here is views\empdelete.dt:

extends layout
block maincontent
  include cssformgrid.dt
  -if(error)
    div.error-div
      span.error-message #{error}
  div.form-grid-wrapper
    h2.center-align Are you sure you want to delete this record?
    form.form-grid(method="post", action="delete_employee")
      span.form-grid-label Employee number:
      span.form-grid-field #{e.empid}
      span.form-grid-label Department:
      span.form-grid-field #{e.deprt}
      span.form-grid-label Salary grade:
      span.form-grid-field #{e.paygd}
      span.form-grid-label Email address:
      span.form-grid-field #{e.email}
      span.form-grid-label First name:
      span.form-grid-field #{e.fname}
      span.form-grid-label Last name:
      span.form-grid-field #{e.lname}
      span.form-grid-label Phone:
      span.form-grid-field #{e.phone}
      span.form-grid-label Street address:
      span.form-grid-field #{e.street}
      span.form-grid-label City:
      span.form-grid-field #{e.city}
      span.form-grid-label Province:
      span.form-grid-field #{e.province}
      span.form-grid-label Postal code:
      span.form-grid-field #{e.postcode}
      span.form-grid-label ID Picture:
      img(src="#{e.photo}", height="80px")
      input(type="hidden", name="id", value="#{e.id}")
      div
      div
        a(href="all_employees")
          button.form-grid-button(type="button") Cancel
        input.form-grid-button(type="submit", value="Delete")

Here is views\empedit.dt:

extends layout
block maincontent
  include cssformgrid.dt
  -if(error)
    div.error-div
      span.error-message #{error}
  div.form-grid-wrapper
    h2.center-align Edit employee details
    form.form-grid(method="post", action="edit_employee", enctype="multipart/form-data")
      label.form-grid-label Employee number
      input.form-grid-input(type="empid", name="e_empid", value="#{e.empid}")
      label.form-grid-label Department
      select#deprt.form-grid-input(name="e_deprt", value="#{e.deprt}")
        -foreach(dep; departments)
          -if(dep == e.deprt)
            option(value="#{dep}", selected) #{dep}
          -else
            option(value="#{dep}") #{dep}
      label.form-grid-label Salary grade
      select#paygd.form-grid-input(name="e_paygd", value="#{e.paygd}")
        -foreach(pay; paygrades)
          -if(pay == e.paygd)
            option(value="#{pay}", selected) #{pay}
          -else
            option(value="#{pay}") #{pay}
      label.form-grid-label Email address
      input.form-grid-input(type="email", name="e_email", value="#{e.email}")
      label.form-grid-label Password
      input.form-grid-input(type="password", name="e_pword", value="#{e.pword}")
      label.form-grid-label First name
      input.form-grid-input(type="text", name="e_fname", value="#{e.fname}")
      label.form-grid-label Last name
      input.form-grid-input(type="text", name="e_lname", value="#{e.lname}")
      label.form-grid-label Phone
      input.form-grid-input(type="text", name="e_phone", value="#{e.phone}")
      label.form-grid-label Street address (no city)
      input.form-grid-input(type="text", name="e_street", value="#{e.street}")
      label.form-grid-label City
      input.form-grid-input(type="text", name="e_city", value="#{e.city}")
      label.form-grid-label Province
      select#province.form-grid-input(name="e_province", value="#{e.province}")
        -foreach(prov; provinces)
          -if(prov[0] == e.province)
            option(value="#{prov[0]}", selected) #{prov[1]}
          -else
            option(value="#{prov[0]}") #{prov[1]}
      label.form-grid-label Postal code
      input.form-grid-input(type="text", name="e_postcode", value="#{e.postcode}")
      label.form-grid-label ID Picture
      img(src="#{e.photo}", height="100px")
      div
      input.form-grid-input(type="file", name="picture")
      input(type="hidden", name="e_photo", value="#{e.photo}")
      input(type="hidden", name="e_id", value="#{e.id}")
      input(type="hidden", name="id", value="#{e.id}")
      div
      div
        a(href="all_employees")
          button.form-grid-button(type="button") Cancel
        input.form-grid-button(type="submit", value="Submit")listall.dt:

Here is views\emplistall.dt:

extends layout
block maincontent
  include csstable.dt
  -if(error)
    div.error-div
      span.error-message #{error}
  div.table-wrapper
    table
      tr
        th Employee Id
        th First name
        th Last name
        th Department
        th Phone number
        th Email address
        th Street address
        th City
        th Province
        th PostCode
        th Action
      -foreach(e; emps)
        tr
          td #{e.empid}
          td #{e.fname}
          td #{e.lname}
          td #{e.deprt}
          td #{e.phone}
          td #{e.email}
          td #{e.street}
          td #{e.city}
          td #{e.province}
          td #{e.postcode}
          td  
            form.form-hidden(method="get", action="edit_employee")
              input(type="hidden", name="id", value="#{e.id}")
              input(type="image", src="images/pencil.ico", height="15px")
            |  
            form.form-hidden(method="get", action="delete_employee")
              input(type="hidden", name="id", value="#{e.id}")
              input(type="image", src="images/trash.ico", height="15px")
            |  

Here is views\employee.dt:

extends layout
block maincontent
  include cssformgrid.dt
  div.form-grid-wrapper
    h2.center-align Employee details
    div.form-grid
      span.form-grid-label Employee number:
      span.form-grid-field #{e.empid}
      span.form-grid-label Department:
      span.form-grid-field #{e.deprt}
      span.form-grid-label Salary grade:
      span.form-grid-field #{e.paygd}
      span.form-grid-label Email address:
      span.form-grid-field #{e.email}
      span.form-grid-label First name:
      span.form-grid-field #{e.fname}
      span.form-grid-label Last name:
      span.form-grid-field #{e.lname}
      span.form-grid-label Phone:
      span.form-grid-field #{e.phone}
      span.form-grid-label Street address:
      span.form-grid-field #{e.street}
      span.form-grid-label City:
      span.form-grid-field #{e.city}
      span.form-grid-label Province:
      span.form-grid-field #{e.province}
      span.form-grid-label Postal code:
      span.form-grid-field #{e.postcode}
      span.form-grid-label ID Picture:
      img(src="#{e.photo}", height="80px")
      div
      div
        a(href="all_employees")
          button.form-grid-button(type="button") Close

Here is views\index.dt:

extends layout
block maincontent
  h2 The Lorem Ipsum Company
  -if(error)
    div.error-div
      span.error-message #{error}
  div.
    Lorem ipsum dolor sit amet, consectetur adipiscing elit.
    Nam nec urna arcu. Quisque eleifend posuere vestibulum.
    In sed magna mauris. Phasellus bibendum ligula et placerat
    vulputate. In non suscipit lectus, a laoreet odio. Donec
    at sapien eu nisi porta condimentum. Morbi non varius ex,
    nec luctus nisl. Aenean varius dui quis arcu auctor luctus.
    Integer efficitur ornare massa, ac suscipit enim sagittis et.
    Proin vestibulum tellus in ipsum ultrices, sed imperdiet
    sapien euismod. Praesent vel facilisis mauris. Proin finibus
    congue tellus, non varius ante. Nullam tincidunt dolor felis.
    Pellentesque non luctus tellus. Curabitur et sapien at justo
    fringilla feugiat et a erat.
    <br /><br />

Here is views\layout.dt:

doctype 5
html
  head
    title Employee Timekeeping System
    include styles.dt
  body
    div.container
      div.menu
        include menu.dt
      div.content
        block maincontent
      div.footer
        include footer.dt

Here is views\menu.dt:

div.menu-item
  a.item-link(href="/") Home
div.menu-item
  a.item-link(href="all_employees") All employees
div.menu-item
  a.item-link(href="#find_employee") Find employee
div.menu-item
  a.item-link(href="add_employee") Add employee
div.menu-item
  a.item-link.item-link-right(href="#login") Login
div#find_employee.modal-form
  div.modal-form-wrapper-find_employee
    form.modal-form-grid(method="post", action="find_employee")
      input.text-control(name="fname", type="text", placeholder=" First name", required)
      input.text-control(name="lname", type="text", placeholder=" Last name", required)
      input#but-reset(type="reset", value="Clear")
      input#but-submit(type="submit", value="Find")
    a.close(href="#close") Cancel
div#login.modal-form
  div.modal-form-wrapper-login
    form.modal-form-grid(method="post", action="login")
      input.text-control(name="email", type="email", placeholder=" email address")
      input.text-control(name="password", type="password", placeholder=" password")
      input#but-reset(type="reset", value="Clear")
      input#but-submit(type="submit", value="Login")
    a.close(href="#close") Cancel

Here is views\footer.dt:

div.copyright Copyright &copy; The Lorem Ipsum Company 2023

Here is views\styles.dt:

:css
  body
  {
    margin: 0;
    padding: 0;
  }
  .container
  {
    display: grid;
    grid-template-rows: 40px auto 30px;
    height: 100%;
    width: 100%;
    margin: 0;
    padding: 0;
  }
  .menu
  {
    position: fixed;
    top: 0;
    width: 100%;
    padding: 10px 0;
    background-color: whitesmoke;
  }
  .menu-item
  {
    display: inline;
  }
  .item-link
  {
    margin-left: 30px;
    font-family: Verdana, Geneva, Tahoma, sans-serif;
    font-size: 18px;
    color: teal;
    text-decoration: none;
  }
  .item-link-right
  {
    float: right;
    margin-right: 30px;
  }
  .modal-form
  {
    position: fixed;
    font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
    top: 0;
    right: 0;
    bottom: 0;
    left: 0;
    background: rgba(0,0,0,0.5);
    z-index: 99999;
    opacity: 0;
    pointer-events: none;
  }
  #login:target, #find_employee:target
  {
    opacity: 1;
    pointer-events: auto;
  }
  .modal-form-grid
  {
    display: grid;
    grid-template: 30px 30px 30px / 1fr 1fr;
    grid-gap: 10px;
  }
  .text-control
  {
    grid-column: 1 / 3;
  }
  #but-reset
  {
    grid-column: 1 / 2;
  }
  #but-submit
  {
    grid-column: 2 / 3;
  }
  .modal-form-wrapper-login
  {
    width: 250px;
    position: absolute;
    right: 0;
    margin-top: 40px;
    padding: 25px 20px;
    border-radius: 10px;
    text-align: center;
    background-color: whitesmoke;
  }
  .modal-form-wrapper-find_employee
  {
    width: 250px;
    position: relative;
    left: 280px;
    margin-top: 40px;
    padding: 25px 20px;
    border-radius: 10px;
    text-align: center;
    background-color: whitesmoke;
  }
  .content
  {
    padding: 40px 30px;
  }
  .footer
  {
    position: fixed;
    bottom: 0;
    width: 100%;    
    background-color: lightgray;
    padding: 5px 0;
  }
  .copyright
  {
    font-family: Verdana, Geneva, Tahoma, sans-serif;
    font-size: 14px;
    text-align: center;
    color: teal;
  }
  .form-hidden
  {
    padding: 0;
    margin: 0;
    display: inline;
  }
  .error-div
  {
    width: 90%;
    margin: 20px auto;
  }
  .error-message
  {
    color: brown;
    font-weight: bold;
  }

And here is dub.json:

{
  "authors": [
    "Owner"
  ],
  "copyright": "Copyright © 2023, Owner",
  "dependencies": {
    "mysql-native": "~>3.2.0",
    "vibe-d": "~>0.9"
  },
  "description": "A simple vibe.d server application.",
  "license": "proprietary",
  "name": "lorem"
}

Now on to the timekeeping system.

Last updated