feat: course list

This commit is contained in:
Jannat Patel
2023-12-05 22:39:00 +05:30
parent 644fb698d8
commit d00da31f84
108 changed files with 47452 additions and 56 deletions

View File

@@ -142,10 +142,20 @@ def add_mentor_to_subgroup(subgroup, email):
@frappe.whitelist(allow_guest=True)
def get_courses():
"""Returns the list of courses."""
return frappe.get_all(
"LMS Course",
fields=["name", "title", "short_introduction", "image"],
filters={"published": True},
)
def get_user_info(user=None):
print(user)
if frappe.session.user == "Guest":
frappe.throw("Authentication failed", exc=frappe.AuthenticationError)
filters = {}
if user:
filters["name"] = user
users = frappe.qb.get_query(
"User",
filters=filters,
fields=["name", "email", "enabled", "user_image", "full_name", "user_type"],
order_by="full_name asc",
distinct=True,
).run(as_dict=1)
print(users)
return users

View File

@@ -196,7 +196,7 @@ def get_instructors(course):
frappe.db.get_value(
"User",
instructor,
["name", "username", "full_name", "user_image"],
["name", "username", "full_name", "user_image", "first_name"],
as_dict=True,
)
)
@@ -1147,3 +1147,86 @@ def change_currency(amount, currency, country=None):
amount = cint(amount)
amount, currency = check_multicurrency(amount, currency, country)
return fmt_money(amount, 0, currency)
@frappe.whitelist(allow_guest=True)
def get_courses():
"""Returns the list of courses."""
courses = frappe.get_all(
"LMS Course",
fields=[
"name",
"title",
"short_introduction",
"image",
"published",
"upcoming",
"status",
"paid_course",
"course_price",
"currency",
],
filters={"published": True},
)
courses = get_course_details(courses)
courses = get_categorized_courses(courses)
return courses
def get_course_details(courses):
for course in courses:
course.tags = get_tags(course.name)
course.lesson_count = get_lesson_count(course.name)
course.enrollment_count = frappe.db.count(
"LMS Enrollment", {"course": course.name, "member_type": "Student"}
)
avg_rating = get_average_rating(course.name) or 0
course.avg_rating = frappe.utils.flt(
avg_rating, frappe.get_system_settings("float_precision") or 3
)
course.instructors = get_instructors(course.name)
if course.paid_course:
course.price = frappe.utils.fmt_money(course.course_price, 0, course.currency)
else:
course.price = _("Free")
if frappe.session.user == "Guest":
course.membership = None
course.is_instructor = False
else:
course.membership = frappe.db.get_value(
"LMS Enrollment",
{"member": frappe.session.user, "course": course.name},
["name", "course", "current_lesson", "progress"],
as_dict=1,
)
course.is_instructor = is_instructor(course.name)
return courses
def get_categorized_courses(courses):
live, upcoming, enrolled, created, under_review = [], [], [], [], []
for course in courses:
if course.upcoming:
upcoming.append(course)
elif course.published:
live.append(course)
elif course.membership:
enrolled.append(course)
elif course.is_instructor:
created.append(course)
elif course.status == "Under Review":
under_review.append(course)
return {
"live": live,
"upcoming": upcoming,
"enrolled": enrolled,
"created": created,
"under_review": under_review,
}

View File

@@ -0,0 +1,286 @@
var N = Object.defineProperty,
S = Object.defineProperties;
var j = Object.getOwnPropertyDescriptors;
var h = Object.getOwnPropertySymbols;
var b = Object.prototype.hasOwnProperty,
w = Object.prototype.propertyIsEnumerable;
var p = (e, s, t) =>
s in e
? N(e, s, {
enumerable: !0,
configurable: !0,
writable: !0,
value: t,
})
: (e[s] = t),
m = (e, s) => {
for (var t in s || (s = {})) b.call(s, t) && p(e, t, s[t]);
if (h) for (var t of h(s)) w.call(s, t) && p(e, t, s[t]);
return e;
},
g = (e, s) => S(e, j(s));
var C = (e, s) => {
var t = {};
for (var a in e) b.call(e, a) && s.indexOf(a) < 0 && (t[a] = e[a]);
if (e != null && h)
for (var a of h(e)) s.indexOf(a) < 0 && w.call(e, a) && (t[a] = e[a]);
return t;
};
import {
l as $,
o,
d as c,
k as r,
F as v,
m as y,
t as l,
n as B,
p as z,
q as A,
e as n,
u,
v as O,
x as q,
y as U,
z as V,
} from "./frappe-ui.8966d601.js";
var _ = {
xmlns: "http://www.w3.org/2000/svg",
width: 24,
height: 24,
viewBox: "0 0 24 24",
fill: "none",
stroke: "currentColor",
"stroke-width": 2,
"stroke-linecap": "round",
"stroke-linejoin": "round",
};
const F = (e) => e.replace(/([a-z0-9])([A-Z])/g, "$1-$2").toLowerCase(),
f =
(e, s) =>
(oe, { attrs: d, slots: x }) => {
var k = oe,
{
size: t,
strokeWidth: a = 2,
absoluteStrokeWidth: i,
color: M,
} = k,
I = C(k, [
"size",
"strokeWidth",
"absoluteStrokeWidth",
"color",
]);
return $(
"svg",
m(
g(
m(
g(m({}, _), {
width: t || _.width,
height: t || _.height,
stroke: M || _.stroke,
"stroke-width": i
? (Number(a) * 24) / Number(t)
: a,
}),
d
),
{
class: [
"lucide",
`lucide-${F(e)}`,
(d == null ? void 0 : d.class) || "",
],
}
),
I
),
[...s.map((L) => $(...L)), ...(x.default ? [x.default()] : [])]
);
},
H = f("BookOpenIcon", [
[
"path",
{ d: "M2 3h6a4 4 0 0 1 4 4v14a3 3 0 0 0-3-3H2z", key: "vv98re" },
],
[
"path",
{ d: "M22 3h-6a4 4 0 0 0-4 4v14a3 3 0 0 1 3-3h7z", key: "1cyq3y" },
],
]),
D = f("StarIcon", [
[
"polygon",
{
points: "12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2",
key: "8f66p6",
},
],
]),
E = f("UsersIcon", [
[
"path",
{ d: "M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2", key: "1yyitq" },
],
["circle", { cx: "9", cy: "7", r: "4", key: "nufk8" }],
["path", { d: "M22 21v-2a4 4 0 0 0-3-3.87", key: "kshegd" }],
["path", { d: "M16 3.13a4 4 0 0 1 0 7.75", key: "1da9ce" }],
]);
const K = {
class: "flex flex-col h-full border border-gray-200 rounded-md shadow-sm mt-5",
},
P = { class: "flex relative top-4 left-4" },
R = { class: "course-card-pills rounded-md border border-gray-200" },
Z = { key: 0, class: "flex flex-1 text-4xl font-bold" },
G = { class: "p-4" },
J = { class: "flex text-base items-center justify-between" },
Q = { class: "flex items-center space-x-1 py-1" },
T = { class: "flex items-center space-x-1 py-1" },
X = { class: "flex items-center space-x-1 py-1" },
Y = { class: "text-2xl font-semibold" },
W = { class: "text-ellipsis truncate text-base" },
ee = {
__name: "CourseCard",
props: { course: { type: Object, default: null } },
setup(e) {
return (s, t) => (
o(),
c("div", K, [
r(
"div",
{
class: z([
"course-image",
{ "default-image": !e.course.image },
]),
style: A({
backgroundImage: "url(" + e.course.image + ")",
}),
},
[
r("div", P, [
(o(!0),
c(
v,
null,
y(
e.course.tags,
(a) => (o(), c("div", R, l(a), 1))
),
256
)),
]),
e.course.image
? B("", !0)
: (o(), c("div", Z, l(e.course.title[0]), 1)),
],
6
),
r("div", G, [
r("div", J, [
r("div", Q, [
n(u(H), { class: "h-4 w-4 text-gray-700" }),
r("span", null, l(e.course.lesson_count), 1),
]),
r("div", T, [
n(u(E), { class: "h-4 w-4 text-gray-700" }),
r(
"span",
null,
l(e.course.enrollment_count),
1
),
]),
r("div", X, [
n(u(D), { class: "h-4 w-4 text-gray-700" }),
r("span", null, l(e.course.avg_rating), 1),
]),
]),
r("div", Y, l(e.course.title), 1),
r("div", W, l(e.course.short_introduction), 1),
(o(!0),
c(
v,
null,
y(e.course.instructors, (a) => (o(), c("div"))),
256
)),
]),
])
);
},
},
se = {
__name: "UserAvatar",
props: { user: { type: Object, default: null } },
setup(e) {
return (s, t) =>
e.user
? (o(),
O(
u(U),
q(
{
key: 0,
class: "",
label: e.user.full_name,
image: e.user.user_image,
},
s.$attrs
),
null,
16,
["label", "image"]
))
: B("", !0);
},
},
te = { class: "container" },
ae = r("div", { class: "text-2xl font-semibold" }, " All Courses ", -1),
re = { class: "grid grid-cols-3 gap-8" },
ne = {
__name: "Courses",
setup(e) {
const s = V({
type: "list",
doctype: "LMS Course",
url: "lms.lms.utils.get_courses",
auto: !0,
});
return (t, a) => (
o(),
c("div", te, [
ae,
r("div", re, [
(o(!0),
c(
v,
null,
y(
u(s).data,
(i) => (
o(),
c("div", null, [
n(ee, { course: i }, null, 8, [
"course",
]),
n(
se,
{ user: i.instructors[0] },
null,
8,
["user"]
),
])
)
),
256
)),
]),
])
);
},
};
export { ne as default };

View File

@@ -0,0 +1 @@
.course-image{height:168px;width:100%;background-size:cover;background-position:center;background-repeat:no-repeat}.course-card-pills{background:#ffffff;margin-left:0;margin-right:.5rem;padding:3.5px 8px;font-size:11px;text-align:center;letter-spacing:.011em;text-transform:uppercase;font-weight:600;width:-moz-fit-content;width:fit-content}.default-image{display:flex;flex-direction:column;align-items:center;background-color:#ededed;color:#525252}

View File

@@ -0,0 +1,206 @@
import {
b as f,
P as g,
T as _,
r as d,
o,
v as l,
w as r,
A as p,
B as C,
C as k,
k as a,
d as c,
F as u,
m,
q as h,
p as b,
} from "./frappe-ui.8966d601.js";
const v = {
name: "FontColor",
props: ["editor"],
components: { Popover: g, Tooltip: _ },
methods: {
setBackgroundColor(t) {
t.name != "Default"
? this.editor
.chain()
.focus()
.toggleHighlight({ color: t.hex })
.run()
: this.editor.chain().focus().unsetHighlight().run();
},
setForegroundColor(t) {
t.name != "Default"
? this.editor.chain().focus().setColor(t.hex).run()
: this.editor.chain().focus().unsetColor().run();
},
},
computed: {
foregroundColors() {
return [
{ name: "Default", hex: "#1F272E" },
{ name: "Yellow", hex: "#ca8a04" },
{ name: "Orange", hex: "#ea580c" },
{ name: "Red", hex: "#dc2626" },
{ name: "Green", hex: "#16a34a" },
{ name: "Blue", hex: "#1579D0" },
{ name: "Purple", hex: "#9333ea" },
{ name: "Pink", hex: "#db2777" },
];
},
backgroundColors() {
return [
{ name: "Default", hex: null },
{ name: "Yellow", hex: "#fef9c3" },
{ name: "Orange", hex: "#ffedd5" },
{ name: "Red", hex: "#fee2e2" },
{ name: "Green", hex: "#dcfce7" },
{ name: "Blue", hex: "#D3E9FC" },
{ name: "Purple", hex: "#f3e8ff" },
{ name: "Pink", hex: "#fce7f3" },
];
},
},
},
y = { class: "p-2" },
B = a("div", { class: "text-sm text-gray-700" }, "Text Color", -1),
P = { class: "mt-1 grid grid-cols-8 gap-1" },
F = ["aria-label", "onClick"],
w = a(
"div",
{ class: "mt-2 text-sm text-gray-700" },
"Background Color",
-1
),
D = { class: "mt-1 grid grid-cols-8 gap-1" },
T = ["aria-label", "onClick"];
function A(t, z, E, R, $, n) {
const i = d("Tooltip"),
x = d("Popover");
return (
o(),
l(
x,
{ transition: "default" },
{
target: r(({ togglePopover: e, isOpen: s }) => [
p(
t.$slots,
"default",
C(k({ onClick: () => e(), isActive: s }))
),
]),
"body-main": r(() => [
a("div", y, [
B,
a("div", P, [
(o(!0),
c(
u,
null,
m(
n.foregroundColors,
(e) => (
o(),
l(
i,
{
class: "flex",
key: e.name,
text: e.name,
},
{
default: r(() => [
a(
"button",
{
"aria-label":
e.name,
class: "flex h-5 w-5 items-center justify-center rounded border text-base",
style: h({
color: e.hex,
}),
onClick: (s) =>
n.setForegroundColor(
e
),
},
" A ",
12,
F
),
]),
_: 2,
},
1032,
["text"]
)
)
),
128
)),
]),
w,
a("div", D, [
(o(!0),
c(
u,
null,
m(
n.backgroundColors,
(e) => (
o(),
l(
i,
{
class: "flex",
key: e.name,
text: e.name,
},
{
default: r(() => [
a(
"button",
{
"aria-label":
e.name,
class: b([
"flex h-5 w-5 items-center justify-center rounded border text-base text-gray-900",
e.hex
? "border-transparent"
: "border-gray-200",
]),
style: h({
backgroundColor:
e.hex,
}),
onClick: (s) =>
n.setBackgroundColor(
e
),
},
" A ",
14,
T
),
]),
_: 2,
},
1032,
["text"]
)
)
),
128
)),
]),
]),
]),
_: 3,
}
)
);
}
const G = f(v, [["render", A]]);
export { G as default };

View File

@@ -0,0 +1,65 @@
import {
b as d,
D as g,
r,
o as m,
d as f,
e as t,
w as s,
j as l,
k as p,
t as u,
} from "./frappe-ui.8966d601.js";
const D = {
name: "Home",
data() {
return { showDialog: !1 };
},
resources: { ping: { url: "ping" } },
components: { Dialog: g },
},
_ = { class: "max-w-3xl py-12 mx-auto" };
function k(e, o, w, C, n, V) {
const a = r("Button"),
c = r("Dialog");
return (
m(),
f("div", _, [
t(
a,
{
"icon-left": "code",
onClick: e.$resources.ping.fetch,
loading: e.$resources.ping.loading,
},
{
default: s(() => [l(" Click to send 'ping' request ")]),
_: 1,
},
8,
["onClick", "loading"]
),
p("div", null, u(e.$resources.ping.data), 1),
p("pre", null, u(e.$resources.ping), 1),
t(
a,
{ onClick: o[0] || (o[0] = (i) => (n.showDialog = !0)) },
{ default: s(() => [l("Open Dialog")]), _: 1 }
),
t(
c,
{
title: "Title",
modelValue: n.showDialog,
"onUpdate:modelValue":
o[1] || (o[1] = (i) => (n.showDialog = i)),
},
{ default: s(() => [l(" Dialog content ")]), _: 1 },
8,
["modelValue"]
),
])
);
}
const B = d(D, [["render", k]]);
export { B as default };

View File

@@ -0,0 +1,151 @@
import {
b as f,
h as I,
D,
G as h,
r as d,
o as m,
d as c,
A as _,
B as y,
C,
e as n,
w as s,
k as r,
t as w,
n as b,
j as u,
F as k,
} from "./frappe-ui.8966d601.js";
const v = {
name: "InsertImage",
props: ["editor"],
expose: ["openDialog"],
data() {
return { addImageDialog: { url: "", file: null, show: !1 } };
},
components: { Button: I, Dialog: D },
methods: {
openDialog() {
this.addImageDialog.show = !0;
},
onImageSelect(t) {
let e = t.target.files[0];
!e ||
((this.addImageDialog.file = e),
h(e).then((i) => {
this.addImageDialog.url = i;
}));
},
addImage(t) {
this.editor.chain().focus().setImage({ src: t }).run(),
this.reset();
},
reset() {
this.addImageDialog = this.$options.data().addImageDialog;
},
},
},
B = {
class: "relative cursor-pointer rounded-lg bg-gray-100 py-1 focus-within:bg-gray-200 hover:bg-gray-200",
},
x = { class: "absolute inset-0 select-none px-2 py-1 text-base" },
S = ["src"];
function V(t, e, i, A, a, o) {
const g = d("Button"),
p = d("Dialog");
return (
m(),
c(
k,
null,
[
_(t.$slots, "default", y(C({ onClick: o.openDialog }))),
n(
p,
{
options: { title: "Add Image" },
modelValue: a.addImageDialog.show,
"onUpdate:modelValue":
e[2] || (e[2] = (l) => (a.addImageDialog.show = l)),
onAfterLeave: o.reset,
},
{
"body-content": s(() => [
r("label", B, [
r(
"input",
{
type: "file",
class: "w-full opacity-0",
onChange:
e[0] ||
(e[0] = (...l) =>
o.onImageSelect &&
o.onImageSelect(...l)),
accept: "image/*",
},
null,
32
),
r(
"span",
x,
w(
a.addImageDialog.file
? "Select another image"
: "Select an image"
),
1
),
]),
a.addImageDialog.url
? (m(),
c(
"img",
{
key: 0,
src: a.addImageDialog.url,
class: "mt-2 w-full rounded-lg",
},
null,
8,
S
))
: b("", !0),
]),
actions: s(() => [
n(
g,
{
variant: "solid",
onClick:
e[1] ||
(e[1] = (l) =>
o.addImage(a.addImageDialog.url)),
},
{
default: s(() => [u(" Insert Image ")]),
_: 1,
}
),
n(
g,
{ onClick: o.reset },
{ default: s(() => [u(" Cancel ")]), _: 1 },
8,
["onClick"]
),
]),
_: 1,
},
8,
["modelValue", "onAfterLeave"]
),
],
64
)
);
}
const F = f(v, [["render", V]]);
export { F as default };

View File

@@ -0,0 +1,120 @@
import {
b as d,
h as g,
I as L,
D as m,
r as i,
o as p,
d as f,
A as D,
B as h,
C as c,
e as l,
w as a,
E as w,
j as _,
F as v,
} from "./frappe-ui.8966d601.js";
const x = {
name: "InsertLink",
props: ["editor"],
components: { Button: g, Input: L, Dialog: m },
data() {
return { setLinkDialog: { url: "", show: !1 } };
},
methods: {
openDialog() {
let t = this.editor.getAttributes("link").href;
t && (this.setLinkDialog.url = t), (this.setLinkDialog.show = !0);
},
setLink(t) {
t === ""
? this.editor
.chain()
.focus()
.extendMarkRange("link")
.unsetLink()
.run()
: this.editor
.chain()
.focus()
.extendMarkRange("link")
.setLink({ href: t })
.run(),
(this.setLinkDialog.show = !1),
(this.setLinkDialog.url = "");
},
reset() {
this.setLinkDialog = this.$options.data().setLinkDialog;
},
},
};
function V(t, e, C, B, n, s) {
const r = i("FormControl"),
u = i("Button"),
k = i("Dialog");
return (
p(),
f(
v,
null,
[
D(t.$slots, "default", h(c({ onClick: s.openDialog }))),
l(
k,
{
options: { title: "Set Link" },
modelValue: n.setLinkDialog.show,
"onUpdate:modelValue":
e[3] || (e[3] = (o) => (n.setLinkDialog.show = o)),
onAfterLeave: s.reset,
},
{
"body-content": a(() => [
l(
r,
{
type: "text",
label: "URL",
modelValue: n.setLinkDialog.url,
"onUpdate:modelValue":
e[0] ||
(e[0] = (o) =>
(n.setLinkDialog.url = o)),
onKeydown:
e[1] ||
(e[1] = w(
(o) => s.setLink(o.target.value),
["enter"]
)),
},
null,
8,
["modelValue"]
),
]),
actions: a(() => [
l(
u,
{
variant: "solid",
onClick:
e[2] ||
(e[2] = (o) =>
s.setLink(n.setLinkDialog.url)),
},
{ default: a(() => [_(" Save ")]), _: 1 }
),
]),
_: 1,
},
8,
["modelValue", "onAfterLeave"]
),
],
64
)
);
}
const b = d(x, [["render", V]]);
export { b as default };

View File

@@ -0,0 +1,200 @@
import {
b as _,
h as C,
D as k,
H as v,
r,
o as u,
d as c,
A as h,
B,
C as w,
e as t,
w as l,
k as x,
j as n,
t as y,
v as U,
n as p,
F,
} from "./frappe-ui.8966d601.js";
const A = {
name: "InsertImage",
props: ["editor"],
expose: ["openDialog"],
data() {
return { addVideoDialog: { url: "", file: null, show: !1 } };
},
components: { Button: C, Dialog: k, FileUploader: v },
methods: {
openDialog() {
this.addVideoDialog.show = !0;
},
onVideoSelect(i) {
let o = i.target.files[0];
!o || (this.addVideoDialog.file = o);
},
addVideo(i) {
this.editor
.chain()
.focus()
.insertContent(`<video src="${i}"></video>`)
.run(),
this.reset();
},
reset() {
this.addVideoDialog = this.$options.data().addVideoDialog;
},
},
},
I = { class: "flex items-center space-x-2" },
N = ["src"];
function S(i, o, b, L, e, a) {
const s = r("Button"),
V = r("FileUploader"),
g = r("Dialog");
return (
u(),
c(
F,
null,
[
h(i.$slots, "default", B(w({ onClick: a.openDialog }))),
t(
g,
{
options: { title: "Add Video" },
modelValue: e.addVideoDialog.show,
"onUpdate:modelValue":
o[2] || (o[2] = (d) => (e.addVideoDialog.show = d)),
onAfterLeave: a.reset,
},
{
"body-content": l(() => [
t(
V,
{
"file-types": "video/*",
onSuccess:
o[0] ||
(o[0] = (d) =>
(e.addVideoDialog.url =
d.file_url)),
},
{
default: l(
({
file: d,
progress: f,
uploading: m,
openFileSelector: D,
}) => [
x("div", I, [
t(
s,
{ onClick: D },
{
default: l(() => [
n(
y(
m
? `Uploading ${f}%`
: e
.addVideoDialog
.url
? "Change Video"
: "Upload Video"
),
1
),
]),
_: 2,
},
1032,
["onClick"]
),
e.addVideoDialog.url
? (u(),
U(
s,
{
key: 0,
onClick: () => {
(e.addVideoDialog.url =
null),
(e.addVideoDialog.file =
null);
},
},
{
default: l(
() => [
n(
" Remove "
),
]
),
_: 2,
},
1032,
["onClick"]
))
: p("", !0),
]),
]
),
_: 1,
}
),
e.addVideoDialog.url
? (u(),
c(
"video",
{
key: 0,
src: e.addVideoDialog.url,
class: "mt-2 w-full rounded-lg",
type: "video/mp4",
controls: "",
},
null,
8,
N
))
: p("", !0),
]),
actions: l(() => [
t(
s,
{
variant: "solid",
onClick:
o[1] ||
(o[1] = (d) =>
a.addVideo(e.addVideoDialog.url)),
},
{
default: l(() => [n(" Insert Video ")]),
_: 1,
}
),
t(
s,
{ onClick: a.reset },
{ default: l(() => [n("Cancel")]), _: 1 },
8,
["onClick"]
),
]),
_: 1,
},
8,
["modelValue", "onAfterLeave"]
),
],
64
)
);
}
const R = _(A, [["render", S]]);
export { R as default };

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1 @@
.form-select{background-image:url("data:image/svg+xml;utf8,<svg fill='none' width='8' xmlns='http://www.w3.org/2000/svg' viewBox='-4 -2 16 16'><path d='M4.5 3.636 6.136 2l1.637 1.636M4.5 8.364 6.136 10l1.637-1.636' stroke='%23333C44' stroke-linecap='round' stroke-linejoin='round'/></svg>")}.spinner[data-v-10b50c78]{animation:rotate-10b50c78 2s linear infinite}.spinner-path[data-v-10b50c78]{stroke-linecap:round;animation:dash-10b50c78 1.5s ease-in-out infinite}@keyframes rotate-10b50c78{to{transform:rotate(360deg)}}@keyframes dash-10b50c78{0%{stroke-dasharray:1,150;stroke-dashoffset:0}50%{stroke-dasharray:90,150;stroke-dashoffset:-35}to{stroke-dasharray:120,150;stroke-dashoffset:-124}}.item{display:block;margin:0;width:100%;text-align:left;background:transparent;border-radius:.4rem;border:1px solid transparent;padding:.2rem .4rem}.item.is-selected{border-color:#000}.ProseMirror{outline:none;caret-color:#171717;word-break:break-word}.ProseMirror-focused:focus-visible{outline:none}.ProseMirror:not(.ProseMirror-focused) p.is-editor-empty:first-child:before{content:attr(data-placeholder);float:left;color:#999;pointer-events:none;height:0}.ProseMirror-selectednode video,img.ProseMirror-selectednode{outline:2px solid #E2E2E2}.mention{font-weight:600;-webkit-box-decoration-break:clone;box-decoration-break:clone}.prose table p{margin:0}.ProseMirror table .selectedCell:after{z-index:2;position:absolute;content:"";inset:0;pointer-events:none;background:#E3F1FD;opacity:.3}.ProseMirror table .column-resize-handle{position:absolute;right:-1px;top:0;bottom:-2px;width:4px;background-color:#e3f1fd;pointer-events:none}.resize-cursor{cursor:ew-resize;cursor:col-resize}.ProseMirror mark{border-radius:3px;padding:0 2px}

View File

@@ -0,0 +1,88 @@
import {
c as u,
a as l,
_ as i,
b as f,
r as p,
o as d,
d as m,
e as _,
f as h,
g as y,
h as g,
s as v,
i as L,
} from "./frappe-ui.8966d601.js";
(function () {
const o = document.createElement("link").relList;
if (o && o.supports && o.supports("modulepreload")) return;
for (const e of document.querySelectorAll('link[rel="modulepreload"]'))
c(e);
new MutationObserver((e) => {
for (const t of e)
if (t.type === "childList")
for (const s of t.addedNodes)
s.tagName === "LINK" && s.rel === "modulepreload" && c(s);
}).observe(document, { childList: !0, subtree: !0 });
function n(e) {
const t = {};
return (
e.integrity && (t.integrity = e.integrity),
e.referrerpolicy && (t.referrerPolicy = e.referrerpolicy),
e.crossorigin === "use-credentials"
? (t.credentials = "include")
: e.crossorigin === "anonymous"
? (t.credentials = "omit")
: (t.credentials = "same-origin"),
t
);
}
function c(e) {
if (e.ep) return;
e.ep = !0;
const t = n(e);
fetch(e.href, t);
}
})();
const E = [
{
path: "/",
name: "Home",
component: () =>
i(
() => import("./Home.24891fef.js"),
[
"assets/Home.24891fef.js",
"assets/frappe-ui.8966d601.js",
"assets/frappe-ui.e894a05e.css",
]
),
},
{
path: "/courses",
name: "Courses",
component: () =>
i(
() => import("./Courses.10129947.js"),
[
"assets/Courses.10129947.js",
"assets/frappe-ui.8966d601.js",
"assets/frappe-ui.e894a05e.css",
"assets/Courses.4fd15046.css",
]
),
},
];
let O = u({ history: l("/"), routes: E });
const P = {};
function b(a, o) {
const n = p("router-view");
return d(), m("div", null, [_(n)]);
}
const A = f(P, [["render", b]]);
let r = h(A);
v("resourceFetcher", L);
r.use(O);
r.use(y);
r.component("Button", g);
r.mount("#app");

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 440 B

View File

@@ -0,0 +1,21 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" href="/favicon.png" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Frappe UI App</title>
<script type="module" crossorigin src="/assets/index.52b6e5cb.js"></script>
<link rel="modulepreload" crossorigin href="/assets/frappe-ui.8966d601.js">
<link rel="stylesheet" href="/assets/frappe-ui.e894a05e.css">
<link rel="stylesheet" href="/assets/index.943a3ec2.css">
</head>
<body>
<div id="app"></div>
<div id="modals"></div>
<div id="popovers"></div>
<script> window.csrf_token = '{{ csrf_token }}'; </script>
</body>
</html>